Prolog:包含断言的规则仅将第一个结果添加到事实

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

我正在尝试预先计算一些东西并将结果保存为程序开头的事实:(简化代码)

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

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

但当我在 SICStus Prolog 中查询文件时,只有第一个结果 cost(1,20) 得到断言:

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

但是,当我直接在 SICStus 序言控制台中输入 assert_all 的右侧时,两个 cost/2 事实都在那里。

| ?- 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

我觉得这个行为很混乱,这是怎么回事?

在您的原始子句中添加一个 fail/0 并添加另一个刚刚成功的子句:

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

这是怎么回事,你写的程序断言了配方的第一笔费用并留下了一个选择点。在回溯时,它最终会断言其他事实(如果它回溯,这就是当您通过在 Sicstus 控制台中按 ; 来请求更多替代方案时发生的情况)。

这个答案的失败驱动循环只是回溯 recipe/2 的每个解决方案并断言其成本。那么第二个子句就成功了。