Prolog: a rule containing assert adds only first result to facts

142 views Asked by At

I'm trying to precompute some stuff and save the results as facts at the beginning of my program: (simplified code)

:- dynamic cost/2.
%recipe(Id,Cost)
recipe(1,20).
recipe(2,40).

assert_all :- recipe(Id,Cost), assert(cost(Id,Cost)).

But only the first result, cost(1,20) gets asserted when I consult the file in SICStus Prolog:

| ?- assert_all.
yes
| ?- cost(Id,Cost).
Id = 1,
Cost = 20 ? ;
no
| ?

However, when I input the right-hand side of assert_all in the SICStus prolog console directly, both cost/2 facts are there.

| ?- recipe(Id,Cost), assert(cost(Id,Cost)).
Id = 1,
Cost = 20 ? ;
Id = 2,
Cost = 40 ? ;
no
| ?- cost(Id,Cost).                         
Id = 1,
Cost = 20 ? ;
Id = 2,
Cost = 40 ? ;
no

I find this behavior very confusing, what's going on?

1

There are 1 answers

0
gusbro On BEST ANSWER

Put a fail/0 in your original clause and add another clause that just succeeds:

assert_all:- 
  recipe(Id,Cost), 
  assert(cost(Id,Cost)),
  fail.
assert_all.

Whats going on is that your procedure as you wrote it asserted the first cost for a recipe and left a choice point. Upon backtracking it would eventually assert the other facts (if it backtracks, which is what is happening when you ask for more alternatives by pressing ; in the Sicstus console).

The fail driven loop of this answer just backtracks every solution for recipe/2 and asserts its cost. Then the second clause just succeeds.