Recursive Prolog predicate for reverse / palindrome

前端 未结 4 2078
北荒
北荒 2020-12-03 21:59
  1. Can I get a recursive Prolog predicate having two arguments, called reverse, which returns the inverse of a list:

    Sample query and expected result:

相关标签:
4条回答
  • 2020-12-03 22:30
    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).
    
    0 讨论(0)
  • 2020-12-03 22:40

    Ad 1: It is impossible to define reverse/2 as a (directly edit thx to @repeat: tail) recursive predicate - unless you permit an auxiliary predicate.

    Ad 2:

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

    But the easiest way is to define such predicates with DCGs:

    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].
    
    0 讨论(0)
  • 2020-12-03 22:42

    Just for curiosity here goes a recursive implementation of reverse/2 that does not use auxiliary predicates and still reverses the list. You might consider it cheating as it uses reverse/2 using lists and the structure -/2 as arguments.

    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).
    
    0 讨论(0)
  • 2020-12-03 22:47

    There isn't an efficient way to define reverse/2 with a single recursive definition without using some auxiliary predicate. However, if this is nevertheless permitted, a simple solution which doesn't rely on any built-ins like append/3 (and should be applicable for most Prolog implementations) would be to use an accumulator list, as follows:

    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 is the reversal predicate which simply 'delegates' to (or, wraps) the accumulator-based version called rev-acc/2, which recursively adds elements of the input list into an accumulator in reverse order.

    Running this:

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

    And indeed as @false has already pointed out (+1),

    palindrome(X) :- rev(X,X). 
    
    0 讨论(0)
提交回复
热议问题