背景信息
Prolog 可以为您的查询搜索不止一种解决方案。
考虑这个程序:
human(alice).
human(bob).
当您查询?- human(X). 时,Prolog 将搜索与您的程序匹配的X 的分配。它将向您展示解决方案X = alice。之后,您可以按. 停止搜索,也可以按; 继续搜索。如果继续,Prolog 会找到X = bob。之后它将停止,因为它已经用尽了所有可能的解决方案:
?- human(X).
X = alice .
?- human(X).
X = alice ;
X = bob.
您可以使用剪切谓词! 控制搜索过程。 cut 谓词切断当前层中的替代路径。所以如果你用这条规则扩展上面的程序:
find_first_human(X) :- human(X), !.
运行查询?- find_first_human(X).只会输出X = alice.,不会搜索更多答案。 Prolog 知道 human(X) 可以通过多种方式解决,但随后 ! 告诉 Prolog 忽略这些替代方案。
将此应用到您的程序中
主要问题是您的最后一个triangle 谓词不需要CONT > 0。因此,当您查询?- triangle(3). 时,Prolog 最终会到达triangular(3,3,0).,它与您的write 规则相匹配。如您所见,您的程序按预期输出3。但是,Prolog 然后发现triangular(3,3,0) 有替代解决方案,因此它提供您继续搜索。您可以按. 停止,或按; 继续。如果你继续,Prolog 将尝试triangular 的最后一条规则,CONT 被解析为0。因此NCONT 变为-1。然后这将进入一个无限循环,其中最后一个 triangular 规则被重复应用,不断递减 CONT。
您可以使用trace. 验证这一点(可以再次使用notrace. 禁用):
?- trace.
?- triangular(3).
Call: (8) triangular(3) ? creep
Call: (9) triangular(3, 0) ? creep
Call: (10) triangular(3, 0, 3) ? creep
...
Call: (13) triangular(3, 3, 0) ? creep
Call: (14) write(3) ? creep
3
Exit: (14) write(3) ? creep
Exit: (13) triangular(3, 3, 0) ? creep
...
true ;
Redo: (13) triangular(3, 3, 0) ? creep
Call: (14) _2076 is 0+ -1 ? creep
Exit: (14) -1 is 0+ -1 ? creep
...
您可以通过将最后一条规则更改为:
triangular(N,AC,CONT) :- CONT > 0,
NCONT is CONT - 1,
NAC is AC + NCONT,
triangular(N,NAC,NCONT).
这禁止 Prolog 应用 triangular(3,3,0) 的规则。当您使用修改后的程序运行查询?- triangular(3). 时,Prolog 应该在到达triangular(3,3,0) 时像以前一样写出3。之后,它检测到可能存在替代解决方案。如果您按;,它会检测到最后一条规则无法应用,因为CONT > 0 约束不成立。然后它停止搜索:
?- triangular(3).
3
true ;
false.
我们可以使用上一节中显示的切割谓词! 进一步简化这一点,将write 规则修改为:
triangular(N,AC,0) :- write(AC), !.
这告诉 Prolog 不要搜索 triangular(3,3,0) 的替代解决方案。当您运行查询 ?- triangular(3). 时,Prolog 应该像以前一样写出 3,然后退出而不进一步搜索:
?- triangular(3).
3
true.