【问题标题】:Recursive Prolog predicate for reverse / palindrome反向/回文的递归 Prolog 谓词
【发布时间】:2011-09-20 12:40:33
【问题描述】:
  1. 我能否得到一个有两个参数的递归 Prolog 谓词,称为 reverse,它返回列表的倒数:

    示例查询和预期结果:

    ?- 反向([a,b,c],L)。 L = [c,b,a]。
  2. 两个参数的递归 Prolog 谓词称为 palindrome,如果给定列表是回文,则返回 true。

    具有预期结果的示例查询:

    ?- 回文([a,b,c])。 错误的。 ?- 回文([b,a,c,a,b])。 真的。

【问题讨论】:

    标签: list prolog reverse palindrome dcg


    【解决方案1】:

    广告 1:不可能将 reverse/2 定义为(直接将 thx 编辑为 @repeat:tail)递归谓词 - 除非您允许辅助谓词。

    广告 2:

    palindrome(X) :- reverse(X,X).
    

    但最简单的方法是使用 DCG 定义此类谓词:

    iseq([]) --> [].
    iseq([E|Es]) --> iseq(Es), [E].
    
    reverse(Xs, Ys) :-
       phrase(iseq(Xs), Ys).
    
    palindrome(Xs) :-
       phrase(palindrome, Xs).
    
    palindrome --> [].
    palindrome --> [E].
    palindrome --> [E], palindrome, [E].
    

    【讨论】:

    • 在这里使用 DCG 是一个不错的解决方案。
    【解决方案2】:

    没有一种有效的方法来定义reverse/2 使用单个递归定义而不使用一些辅助谓词。但是,如果仍然允许这样做,一个不依赖于任何内置函数(如 append/3)(并且应该适用于大多数 Prolog 实现)的简单解决方案将是使用 累加器列表,如下:

    rev([],[]).
    rev([X|Xs], R) :-
        rev_acc(Xs, [X], R).
    
    rev_acc([], R, R).
    rev_acc([X|Xs], Acc, R) :-
        rev_acc(Xs, [X|Acc], R).
    

    rev/2 是一个反向谓词,它简单地“委托”(或包装)基于累加器的版本rev-acc/2,它将输入列表的元素以相反的顺序递归地添加到累加器中。

    运行这个:

    ?- rev([1,3,2,x,4],L).
    L = [4, x, 2, 3, 1].
    

    确实正如@false 已经指出的那样 (+1),

    palindrome(X) :- rev(X,X). 
    

    【讨论】:

      【解决方案3】:

      出于好奇,这里有一个 reverse/2 的递归实现,它不使用辅助谓词并且仍然反转列表。您可能会认为它作弊,因为它使用 reverse/2 使用列表和结构 -/2 作为参数。

      reverse([], []):-!.
      reverse([], R-R).
      reverse(R-[], R):-!.
      reverse(R-NR, R-NR).
      reverse([Head|Tail], Reversed):-
        reverse(Tail, R-[Head|NR]),
        reverse(R-NR, Reversed).
      

      【讨论】:

      • 不错的尝试,但不正确。反正我给你+1了。 reverse(1-[], Ys). 应该失败,但 Ys = 1. 成功然后,reverse(Xs, Ys), Xs = [1]. 应该成功但失败。所以你不是在作弊,而只是在执行另一个程序。我们同意不将其称为谓词 - 我想。
      • @false。你说得对!。这仅适用于正确的输入列表。
      • reverse(Xs, [1]). 这不是正确的输入列表吗?它以Xs = [1]-[]. 成功
      • 好吧,你打败了我 ;) 它只能单向工作,假设第一个参数是一个正确的列表,第二个参数是另一个列表或未实例化的变量。将在几分钟内删除答案;)
      • 留下你的答案!人们通常认为类似的事情可能会奏效。
      【解决方案4】:
      conca([],L,L).
      conca([X|L1],L2,[X|L3]):- conca(L1,L2,L3).
      rev([],[]).
      rev([X|Y],N):- rev(Y,N1),conca(N1,[X],N).
      palindrome([X|Y]):- rev([X|Y],N),equal([X|Y],N).
      equal([X],[X]).
      equal([X|Y],[X|Z]):- equal(Y,Z).
      

      【讨论】:

      • -1。你的坏名谓词之间没有任何行,conca/3 只是append/3 的副本,它是 ISO,palindrome/1 破坏列表没有任何好处(除了防止空列表无缘无故地成为回文),@987654325 @ 对 =/2 没有任何改进,只是它不必要地受到更多限制。 “新的不是好的,好的不是新的。”
      猜你喜欢
      • 2018-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      相关资源
      最近更新 更多