2011-06-22 24 views
7
  1. mogę dostać rekurencyjną Prolog orzecznik posiadający dwa argumenty, zwanej odwróconej, która zwraca odwrotność listy:Recursive Prolog predykatu do tyłu/palindromu

    zapytanie Sample i oczekiwany wynik:

     
    ?- reverse([a,b,c], L). 
    L = [c,b,a]. 
    
  2. Rekurencyjny predykat Prologu z dwoma argumentami o nazwie palindrome, który zwraca wartość true, jeśli podana lista jest palindromem. Zapytanie

    próbki z oczekiwanego rezultatu:

     
    ?- palindrome([a,b,c]). 
    false. 
    
    ?- palindrome([b,a,c,a,b]). 
    true. 
    

Odpowiedz

6

Ad 1: To jest niemożliwe do zdefiniowania reverse/2 jako ( bezpośrednio edycji thx do @repeat tail) rekurencyjnego orzecznika - jeśli nie zezwalają orzeczenie pomocnicze.

Ad 2:

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

Ale najprostszym sposobem jest zdefiniowanie takich predykatów z 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]. 
+4

Korzystanie DCGs jest ładne rozwiązanie tutaj. – sharky

5

Nie jest skutecznym sposobem definiowania reverse/2 z jednym rekurencyjnej definicji bez korzystania jakiś pomocniczy predykat. Jeśli jednak mimo wszystko jest dozwolone, to proste rozwiązanie, które nie opiera się na żadnych wbudowanych ins jak append/3 (i powinny być stosowane do większości implementacji Prolog) byłoby użyć listy akumulatora, co następuje:

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 jest orzecznikiem odwrócenie, które po prostu „delegatów” (lub, okłady) wersja akumulator opartych o nazwie rev-acc/2, który rekursywnie dodaje elementy z listy wejściowej do akumulatora w odwrotnej kolejności.

Running to:

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

i rzeczywiście jak @false zwracał już uwagę (+1),

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

Tylko dla ciekawości tu idzie rekurencyjną implementację odwrotnej/2, który nie użyj pomocniczych predykatów i nadal odwraca listę. Możesz uważać to za oszustwo, ponieważ używa odwrotnego/2 list i struktury -/2 jako argumentów.

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

Niezła próba, ale niepoprawna. I tak dałem ci +1. 'reverse (1- [], Ys) .' powinien się nie udać, ale mu się to uda z' Ys = 1.' Następnie 'reverse (Xs, Ys), Xs = [1] .' powinien się powieść, ale się nie powiedzie. Więc nie oszukujesz, ale po prostu wdrażasz inną procedurę. Zgadzamy się nie nazywać tego orzeczeniem - przypuszczam. – false

+1

@false. Masz rację!. Będzie działać tylko z odpowiednimi listami wejściowymi. – gusbro

+0

'reverse (Xs, [1]).' Czy to nie jest właściwa lista wejściowa? Udaje mu się to z 'Xs = [1] - [].' – false

0
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

-1. Brak linii między twoimi źle określonymi predykatami, 'conca/3' jest po prostu kopią' append/3' która jest ISO, 'palindrome/1' niszczą listę bez żadnego zysku (z wyjątkiem zapobiegania pustym listom z palindromów za nie powód), a "równy/2" nie jest poprawą w stosunku do '=/2', z tym wyjątkiem, że jest niepotrzebnie bardziej ograniczony. "Co nowego nie jest dobre, a co dobre nie jest nowe". –