(is)/2
对第二个参数中的实例化非常敏感。这意味着您不能以完全相关的方式使用它。你可以问X is 1+1.
,你甚至可以问2 is 1+1.
但你不能问:2 is X+1
。
因此,当您使用诸如 之类的谓词进行编程时(is)/2
,您必须想象谓词将用于哪些模式。这样的考虑很容易导致错误,特别是如果您刚刚开始。但不用担心,更熟练的程序员仍然会遇到此类问题。
在几个 Prolog 系统中有一个干净的替代方案:在 SICStus、YAP、SWI 中,有一个library(clpfd)
允许您表达整数之间的关系。通常这个库用于约束编程,但您也可以将它用作(is)/2
整数的安全和干净的替代品。更重要的是,这个库通常被非常有效地编译,使得生成的代码在速度上与(is)/2
.
?- 使用模块(库(clpfd))。
真的。
?- X #= 1+1。
X = 2。
?- 2 #= 1+1。
真的。
?- 2 #= X+1。
X = 1。
所以现在回到你的程序,你可以简单地写:
移动2(X,Y,1):-边缘(X,Y)。
move2(X,Y,N0):- N0 #>= 1, N0 #= N1+1, edge(X,Z), move2(Z,Y,N1)。
您现在可以根据需要获得所有距离。
但还有更多...
为确保move2/3
实际终止,请尝试:
?- move2(A, B, N),假的。
错误的。
现在我们可以确定它move2/3
总是终止。总是?假设您添加了进一步的优势:
edge(f, f).
现在上面的查询循环。但是您仍然可以使用您的程序来发挥自己的优势!确定节点数:
?- setof(C,A^B^(edge(A,B),member(C,[A,B])),Cs), 长度(Cs, N)。
Cs = [a, b, c, d, e, f, g, h],
N = 8。
所以最长的路径只需 7 步!
现在您可以再次询问查询,但现在通过限制N
为小于或等于 7 的值:
?- 7 #>= N, move2(A,B, N), false。
错误的。
有了这个额外的约束,你又得到了一个终止定义!没有更多的循环。