Prolog, Mån 16/9 Rebecca Jonson Repetition • Predikat med listor – hänga_gubbe/1 hänga_gubbe([A,n,B,C,D,t,A,E]). ?- hänga_gubbe("infantil"). yes • Rekursiva predikat med listor – lika_långa/2 lika_långa([],[]). lika_långa([_|Xs],[_|Ys]):lika_långa(Xs,Ys). Repetition forts. member/2 kollar om en term är ett element i en lista – Basfall: Elementet är huvud på listan – Rekursivt fall: Elementet finns i svansen member(X,[X|_]). member(X,[_|Xs]) :- member(X,Xs). Repetition forts. • append/3, som kallas conc i kursboken, sätter ihop två listor till en tredje lista. – Basfall: den första listan är tom – resultatet blir den andra listan – Rekursivt fall: den första listan har huvud och svans. I så fall vet vi att den första listans och resultatlistans första element är samma. Resten av resultatlistan fås genom att sätta ihop den första listans svans med den andra listan. append([],Xs,Xs). append([X|Xs],Ys,[X|Zs]) :append(Xs,Ys,Zs). ?- append([1,2],[3],X). Sätter ihop en lista. X = [1,2,3] ? ?- append(Xs,Ys,"lisa"). Kan också dela upp en lista. Dagens föreläsning • Rekursion forts. • Ordningen på regler och klausuler i rekursiva predikat, terminering • Mappning/Översättning • Filtrering Rekursion • Ett predikat är rekursivt om det anropar sig själv med någon del av ett argument. För att rekursionen ska lyckas måste det dessutom finnas minst en klausul utan något rekursivt anrop. – Rekursionsfall: regler som någonstans i kroppen anropar sig själv – Basfall: fakta eller regler som inte anropar sig självt. Regel-, klausul- ordning Utan basfall som stoppar rekursionen kan Prolog aldrig terminera. p:- p. Ordningen på regler och klausuler hos rekursiva predikat påverkar predikatets möjlighet till termination. • Tips Basfallsregeln först, sedan rekursionsregeln. Rekursionsklausul efter basfallsklausul i kroppen. Regelordning lika_långa([],[]). lika_långa([_|Xs],[_|Ys]):lika_långa(Xs,Ys). lika_långa2([_|Xs],[_|Ys]):lika_långa2(Xs,Ys). lika_långa2([],[]). ?- lika_långa(X,Y). Ger svar på alla möjliga listor och börjar med svaret att de båda variablerna är tomma listor, sedan en variabel följt av tomma listan, två variabler följt av tomma listan osv. ?- lika_långa2(X,Y). Loopar eftersom den hela tiden kommer gå in i första regeln med de nya variablerna. Klausulordning barn(anna,maria). barn(maria,alva). barn(alva,eva). härstamma(X,Y):-barn(X,Y). härstamma(X,Y):-barn(X,Z),härstamma(Z,Y). härstamma2(X,Y):-barn(X,Y). härstamma2(X,Y):-härstamma2(Z,Y),barn(X,Z). härstamma3(X,Y):-härstamma3(Z,Y),barn(X,Z). härstamma3(X,Y):-barn(X,Y). Klausulordning forts. ?- härstamma(alva,Vem). Vem=eva; No ?- härstamma2(alva,Vem). Vem=eva; LOOP!!! ?- härstamma3(alva,Vem). Vad gör prolog i det här fallet? Mappning, översättning Ofta vill man applicera något predikat på varje element i en given lista för att få en annan lista (en mappning eller översättning av listan) Exempel: Predikatet trans översätter svenska ord till engelska ?- trans("bil", X). X = "car” ?- trans("hus", Y). Y = "house” ?- trans("en", Z). Z = "a” ?- trans("ett", Z). Z = "a" Translist Nu kan vi skriva ett predikat som översätter svenska meningar givna som listor av ord till engelska meningar. • Basfallet är den minsta möjliga listan, i det här fallet tomma listan som översätts till sig själv. translist([], []). • Rekursionsfallet är när vi har ett huvud (ett svenskt ord) och en svans (en svensk mening). Huvudet översätts till ett engelskt ord och svansen översätts till en engelsk mening, och resultatet kommer då att ha det engelska ordet som huvud och den engelska meningen som svans. translist([SveOrd|SveMening], [EngOrd|EngMening]) :trans(SveOrd, EngOrd), translist(SveMening,EngMening). Translist forts. Observera att det går alldeles utmärkt att översätta från svenska till engelska, så länge predikatet trans/2 klarar av båda riktningarna. ?- translist(["en","bil","är","i","ett","hus"], Engelska). Engelska = ["a","car","is","in","a","house"] ?-translist(Svenska,["a","car","is","in","a","house"]). Svenska = ["en","bil","är","i","en","hus"] ; Svenska = ["en","bil","är","i","ett","hus"] ; Svenska = ["ett","bil","är","i","en","hus"] ; Svenska = ["ett","bil","är","i","ett","hus"] ; Mappning forts. En variant på mappning är att en term översätts till flera termer Ex. svenska ordet ”bilen” till frasen ”the car” Vi gör om översättningspredikatet till översätta ord till en lista med ord. ?- trans2("bil", X). X = ["car"] ?- trans2("bilen", X). X = ["the","car"] Translist2/2 • Basfallet är som förut. translist2([], []). • Rekursionsfallet översätter huvudet till en lista, och svansen till en annan lista. Slutligen konkateneras de två listorna med append/3 till en resultatlista. translist2([Ord|Mening], Resultat) :trans2(Ord, Resultat1), translist2(Mening, Resultat2), append(Resultat1, Resultat2, Resultat). I denna version kan vi endast översätta i en riktning, från svenska till engelska. ?- translist2(["bilen","är","i","huset"], Engelska). Engelska = ["the","car","is","in","the","house"] Filtrering Filtrering: Man vill endast plocka ut vissa element ur listan, andra ska kastas. • Antag att vi har ett predikat behåll/1 som säger om en term ska behållas och ett predikat kasta/1 som säger om en term ska kastas bort. Antag dessutom att de termer som ska behållas är de positiva talen (inklusive noll), och de som ska kastas är de negativa. ?- behåll(3). Yes ?- behåll(-3). No ?- kastas(-3). Yes ?- kastas(0). no Filtrering forts. Då kan vi tillverka predikatet positiva/2 som tar en lista med tal, och behåller de positiva talen som resultat. Vi har ett basfall och två rekursionsfall. • Basfallet är åter igen tomma listan. positiva([], []). • Det första rekursionsfallet är när vi har ett huvud som ska behållas, då stoppar vi in huvudet i resultatet och filtrerar svansen. positiva([Pos|Resten], [Pos|Positiva]) :behåll(Pos), positiva(Resten, Positiva). • Det andra rekursionsfallet är när huvudet ska kastas, i vilket fall vi inte stoppar in det i resultatet. positiva([Neg|Resten], Positiva) :kasta(Neg), positiva(Resten, Positiva). Filtrering ?- positiva([1,2,3,4], Lista). Lista = [1,2,3,4] ?- positiva([-1,2,-3,4], Lista). Lista = [2,4] ?- positiva([-1,-2,-3,-4], Lista). Lista = [] Tack för idag!