【问题标题】:How to fix this list reversal?如何修复此列表反转?
【发布时间】:2021-10-09 06:27:49
【问题描述】:

以下 Prolog 程序定义了一个谓词 rev/2 用于反转传入第一个参数的列表,从而导致传入第二个参数的列表:

rev([], []).
rev([XH|XT], Y) :-
  rev(XT, Z),
  append(Z, [XH], Y).

append([], Y, Y).
append([XH|XT], Y, [XH|ZT]) :-
  append(XT, Y, ZT).

以下 Prolog 程序是 rev/2 的替代实现:

rev(X, Y) :-
  revappend(X, [], Y).

revappend([], Y, Y).
revappend([XH|XT], Y, Z) :-
  revappend(XT, [XH|Y], Z).

在这种参数模式下,两个程序都按预期工作:

?- rev([a, b, c], Y).
   Y = [c, b, a]
;  false.

但是这两个程序在这种参数模式下都耗尽了查询资源:

?- rev(X, [a, b, c]).
   X = [c, b, a]
;
Time limit exceeded

问题:

  1. 如何修复这两个程序?
  2. 两个程序是否等效?

【问题讨论】:

  • 他们都提供了第一个答案,但他们陷入了第二个无限计算。尝试执行:trace, rev(X, [a, b, c]).,你会明白为什么两者都没有终止
  • @damianodamiano 随意纠正答案。
  • @Maggyero 我猜这是弗洛伊德的失误,right 与 write。我拥有的不仅仅是我的份额。
  • @GuyCoder 哎呀,我猜你在写。

标签: list prolog reverse termination failure-slice


【解决方案1】:

在这两个程序中,第三个参数对(通用)终止没有影响,如以下故障切片所示:

rev([], []) :- false。 转([XH|XT],Y):- 转(XT,Z),假, 追加(Z,[XH],Y)。

Y 可以随心所欲,它永远不会导致这个片段失败。因此它对终止没有影响。它是终止中立。

转(X,Y):- 重新附加(X,[],Y),假。 revappend([], Y, Y) :- false。 重新附加([XH|XT],Y,Z):- 重新附加(XT,[XH|Y],Z),假。

同样,revappend/3 中的第三个参数只是被移交,没有任何可能导致失败并因此终止。

为了解决这个问题,必须添加一些东西来专门化剩余的可见部分。一个观察结果是第一个和最后一个参数的列表长度是相同的。因此添加额外的第四个参数以确保两个参数的长度相同将有助于获得optimal 终止条件:

转(X,Y):- 重新附加(X,[],Y,Y)。 重新附加([],Y,Y,[])。 重新附加([XH|XT],Y,Z,[_|Ylen]):- 重新附加(XT,[XH|Y],Z,Ylen)。

下面是这个程序的概括,以便更好地理解终止是如何受参数影响的:

转(X,Y):- 重新附加(X,_,_,Y)。 重新附加([],_,_,[])。 重新附加([_|XT],_,_,[_|Ylen]):- 重新附加(XT,_,_,Ylen)。

所以第二个和第三个参数被_ 替换。这个概括现在正好是same_length/2。

【讨论】:

  • 感谢您的分析和解决方案,它就像一个魅力! ‘因此添加了第四个参数来确保第一个和第三个参数的长度相同’ 没有这个第四个参数不是已经保证了吗?我找不到目标 revappend 在第一个和第三个参数长度不同的情况下返回 yes。
  • 我查看了跟踪 (trace, rev(X, [a, b, c]).),现在我了解了您的长度参数。不管有没有,递归调用都会以当前模式revappend(_, [_, _, _], [a, b, c]) 与基本子句revappend([], Y, Y, []). 匹配,产生[c, b, a] 作为第一个结果。然后解释器继续搜索,没有你的长度参数,相同的模式与通用子句revappend([XH|XT], Y, Z)匹配,因此调用revappend(XT, [XH|Y], Z),将当前模式更新为revappend(_, [_, _, _, _], [a, b, c])(Y有4个项目> 3),等等.
  • @Maggyero:查看源代码并发现一些部分比查看跟踪要简单得多。有many alternatives。出于同样的原因,我迷路时从不检查汽车的发动机。相反,我使用地图等,虽然我知道引擎在某种程度上是我到达迷路的地方的原因......
  • 这对您来说可能看起来微不足道,但我认为我需要更多经验才能仅查看代码并立即理解您的解决方案。如果没有痕迹或在一张纸上写下每一步,我想我永远不会理解。看到实际的模式匹配对我很有帮助。再次感谢这个很棒的答案,我真的很感激。
  • @Maggyero:rev([_|_],[]).
猜你喜欢
  • 2022-01-11
  • 2021-12-13
  • 2013-11-15
  • 2016-02-08
  • 1970-01-01
  • 2016-02-28
  • 2018-02-14
  • 2011-04-25
相关资源
最近更新 更多