【问题标题】:Prolog logic flowProlog逻辑流程
【发布时间】:2012-04-16 20:44:06
【问题描述】:

我对 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).

【问题讨论】:

  • 不应该将F 评估为D-E,而不是D+E?您希望递归距离是总距离减去每次仅与第一项的距离。我也对distance(T1, T2, S); 这行感到困惑,您能对此发表评论吗?
  • N/M,我明白你现在在做什么......在最后一个参数中累积距离的总和。我认为这有点令人困惑,但正确。所以唯一的问题是奇怪的印刷。我认为这与您缺乏真正的基本案例有关。在您的方法中, distance([],[],0) 不会是真的。另请注意您的代码在运行时如何挂起,等待额外的“。”返回 true 后。

标签: prolog logic


【解决方案1】:

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

您最好考虑如何递归建模来解决这个问题。在这种情况下,您可以例如在输入列表为空时拆分问题,而当它们不是时(我在这里假设使用空列表调用您的过程将产生 0 作为结果)。

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

所以我们为 distance/3 创建一个事实,它只会调用另一个使用这个累加器的过程:

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

我们使用累加器在您的代码中保存项目差异平方和 (A-B)*(A-B) 的部分结果:

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

distance([],[],S,F) :-
  F is sqrt(S).

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

我们现在跟随递归步骤,计算每个列表中第一项的平方项差异并进行递归。

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.

【讨论】:

  • 当然!感谢您如此清晰简洁地解释一切。我使用了您给我的更改,现在它可以工作了。谢谢!
【解决方案2】:

我不明白format 函数的用法,所以我能做的就是提供我自己的尝试。我认为您的尝试有一个缺点,即在递归的基本情况方面没有明确说明。

考虑下面我的方法:

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).

【讨论】:

  • 请注意,您正在计算另一个函数。例如,您将使用 3 个项目的列表 (A1-B1)^2 + sqrt((A2-B2)^2 + sqrt((A3-B3)^2)^2)^2。您的第二个基本情况也不是必需的。
  • 使用第二种基本情况不会比没有情况更快吗?也许在数值上也更健壮(尽管通常这在 Prolog 中不是问题)。
  • 问题是不太清楚。如果您希望它更快、更健壮,您可能应该使用累加器来允许尾递归(否则您可能会遇到堆栈问题)
  • 嗯,我认为我的方法的好处是它更清晰,但你提出了很好的观点。谢谢!
【解决方案3】:

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

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).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-20
    • 2012-06-11
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    相关资源
    最近更新 更多