Prolog逻辑流

Prolog逻辑流,prolog,logic,Prolog,Logic,我对Prolog完全陌生,正在做家庭作业。我的程序应该获取两个长度相等的列表,并执行D=sqrt((X1-Y1)^2+(X2-Y2)^2+…+(XN-YN)^2)。我编写代码是为了得到正确的答案,但它没有正确地表示出来。我认为这可能是逻辑流的一个问题,因为它似乎在一个无限循环中结束。它应该看起来像: ?- distance([1,2,3], [2,3,4], D). D = 1.732051. 我的代码给出了正确的结果,但它会像这样打印: ?- distance([1,2,3],[2,3,4]

我对Prolog完全陌生,正在做家庭作业。我的程序应该获取两个长度相等的列表,并执行D=sqrt((X1-Y1)^2+(X2-Y2)^2+…+(XN-YN)^2)。我编写代码是为了得到正确的答案,但它没有正确地表示出来。我认为这可能是逻辑流的一个问题,因为它似乎在一个无限循环中结束。它应该看起来像:

?- distance([1,2,3], [2,3,4], D).
D = 1.732051.
我的代码给出了正确的结果,但它会像这样打印:

?- distance([1,2,3],[2,3,4],D).
1.732051
true
只是因为我有一行在那里打印结果。它也不会结束(无周期),直到我点击回车键,这就是为什么我担心我有一个循环。如何重新表述代码或重定向逻辑,使其正常打印

distance([],[],D) :-
  F is sqrt(D),
  format("~f~n", [F]).

distance([A|T1], [B|T2], D) :-
  var(D),
  S is (A-B)*(A-B),
  distance(T1, T2, S);
  C is A-B,
  E is C*C,
  F is D+E,
  distance(T1, T2, F).

您的程序不会进入无限循环,否则您很可能会在某个点出现堆栈溢出错误。 发生的情况是,您的代码留下了一个开放的选择点,因此最终解释器尝试重做(未成功)。 您没有得到预期的结果,因为调用过程中使用的变量D从未绑定

你最好考虑如何递归建模来解决这个问题。例如,在这种情况下,您可以在输入列表为空和不为空时分割问题(我在这里假设使用空列表调用您的过程将得到0)

因此,在这个场景中,您将创建两个子句,一个用于基本情况(空列表),另一个用于递归步骤。我还将使用prolog中使用的一种常见方法,包括使用累加器

因此,我们为distance/3创建一个事实,它将调用另一个使用此累加器的过程:

distance(L1,L2,F) :-
    distance(L1, L2, 0, F).
我们使用累加器在您的代码中保存项差平方和(A-B)*(A-B)的部分结果:

现在我们从基本情况(空列表)开始:

在这里,我们声明当没有更多的项目时,结果是累加器的平方根

我们现在执行递归步骤,该步骤计算每个列表中第一个项的平方项差并执行递归

distance([A|T1], [B|T2], D, SQRT) :-
  S is D+(A-B)*(A-B),
  distance(T1, T2, S, SQRT).
现在我们完成了:

?- distance([1,2,3],[2,3,4],D).
D = 1.7320508075688772.

我不理解
格式
函数的用法,所以我所能做的就是提供我自己的尝试。我认为您的尝试有一个缺点,即它并没有在递归的基本情况中明确说明

distance([A|T1], [B|T2], D, SQRT) :-
  S is D+(A-B)*(A-B),
  distance(T1, T2, S, SQRT).
考虑我的方法如下:

distance([],[],0).
distance([A],[A],0).
distance([A|T1],[B|T2],D) :-
    distance(T1,T2,F),
    D is sqrt((A-B)*(A-B) + F*F).

我认为你应该使用累加器:

distance(L1, L2, D) :- 
    distance(L1, L2, 0, D).

distance([], [], TT, D) :-
    D is sqrt(D).

distance([X1 | Y1], [X2 | Y2], TT, D) :-
    TT1 is TT + (X1 - X2) * X1 - X2),
    distance(Y1, Y2, TT1, D).

不应该将
F
评估为
D-E
,而不是
D+E
?您希望递归距离是总距离减去每次仅与第一项的距离。我也被直线
距离(T1,T2,S)弄糊涂了(A1-B1)^2+sqrt((A2-B2)^2+sqrt((A3-B3)^2)^2)^2
。而且你的第二个基本情况是不必要的。有第二个基本情况会比没有更快吗?也许在数值上更稳健(虽然在Prolog中这通常不是问题),问题是它不太清晰。如果您希望它更快、更健壮,那么您可能应该使用累加器来允许尾部递归(否则您可能会有堆栈问题)。嗯,我认为我的方法的好处是它更清晰,但您提出了非常好的观点。谢谢当然谢谢你把一切解释得如此清楚和简洁。我使用了你给我的改变,现在它工作了。谢谢