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!