1 Logikprogrammering ons 11/9 David Hjelm
2 Repetition Listor är sammansatta termer. De består av en ordnad mängd element. Elementen i en lista kan vara vilka termer som helst. Listor läses från vänster till höger, det ”vänstraste” elementet är alltså det första och det ”högraste” är det sista i listan. [första,andra,tredje,fjärde] En lista med atomer [Två,Variabler] En lista med variabler [1,blandad,Lista] En lista med olika typer av termer [] Den tomma listan (utan element) [[en,lista],[av],[listor]] En lista av listor
3 Repetition Antingen är en lista den tomma listan eller så består den av huvud och svans. Huvudet på en lista är det första elementet i listan. Svansen är en lista med resten av elementen. Det sista elementet i en lista har alltid tomma listan som svans. –Listan [a,b,c] består av huvudet a och svansen [b,c] som består av huvudet b och svansen [c] som har huvudet c och svansen []. Den tomma listan har varken huvud eller svans.
4 Repetition En lista kan delas upp i huvud och svans så här: [Huvud|Svans] Generellt kan en (icke-tom) lista skrivas som [A,B,…,K|Resten] där A,B,…,K är de första elementen i listan och Resten är resten av listan. [a,b,c] är samma som [a|[b,c]] som är samma som [a,b|[c]] som är samma som [a,b,c|[]]
5 Repetition Tecken är atomer av längd 1 Strängar är listor med tecken Strängar skrivs i SICStus prolog som ”sträng” - vilket bara är ett enklare sätt att skriva listan [s,t,r,ä,n,g] Motsvarigheten till den tomma listan [] kallas den tomma strängen ””. Den tomma listan och den tomma strängen är precis samma sak. –”pelle” är samma som [p,e,l,l,e] som är samma som [p,e,l,l,e|[]] som är samma som [p,e,l,l,e|””]
6 Dagens föreläsning Predikat med listor –hänga_gubbe/1 Rekursiva predikat med listor –lika_långa/2 –member/2 –append/3
7 Predikat med listor – hänga gubbe/1 hänga_gubbe/1 lyckas för listor med exakt 8 element, där det andra och sjätte elementet är 'n' och 't', och det första och sjunde elementet är lika: hänga_gubbe([A,n,B,C,D,t,A,E]). ?- hänga_gubbe("Lisa och Pelle"). no ?- hänga_gubbe("infantil"). yes
8 hänga_gubbe/1 forts hänga_gubbe([A,n,B,C,D,t,A,E]). ?- hänga_gubbe([A,A,B,A,A,B|As]). A = n, B = t, As =[n,_1] ?- hänga_gubbe([A,A,A,A|As]). A = n, As = [_1,t,n,_2] ?- hänga_gubbe([A,A,A,A,A,A|As]). no
9 Rekursiva predikat med listor Listor kan vara hur långa som helst. Om man ska skriva predikat som gäller för alla listor, behövs oftast rekursion. Vi vill skriva ett predikat som kollar om två listor är lika långa. Man skulle kunna skriva det så här, som en stor mängd fakta: lika_långa([],[]). lika_långa([_,_],[_,_]). lika_långa([_,_,_],[_,_,_]).... Kommer ändå aldrig att täcka in alla listor, eftersom listor kan vara hur långa som helst.
10 lika_långa/2 Vi använder rekursion istället. I rekursiva predikat har man alltid (minst) ett basfall där rekursionen stannar och ett rekursivt fall som innehåller det rekursiva anropet. –Basfall: Tomma listan och tomma listan är lika långa. –Rekursivt fall: Två listor är lika långa om deras svansar är lika långa lika_långa([],[]). lika_långa([_|Xs],[_|Ys]):- lika_långa(Xs,Ys).
11 lika_långa/2 forts Vårt predikat: lika_långa([],[]). lika_långa([_|Xs],[_|Ys]):- lika_långa(Xs,Ys). ?- lika_långa(”sverige",”danmark"). yes ?- lika_langa("sverige","norge"). no
12 lika_långa/2 forts Ungefär så här fungerar det när prolog kommer fram till svaret för ?lika_långa(”sverige”,”danmark”) : –[s,v,e,r,i,g,e] och [d,a,n,m,a,r,k] är lika långa om [v,e,r,i,g,e] och [a,n,m,a,r,k] är lika långa. –[v,e,r,i,g,e] och [a,n,m,a,r,k] är lika långa om [e,r,i,g,e] och [n,m,a,r,k] är lika långa –[e,r,i,g,e] och [n,m,a,r,k] är lika långa om [r,i,g,e] och [m,a,r,k] är lika långa –[r,i,g,e] och [m,a,r,k] är lika långa om [i,g,e] och [a,r,k] är lika långa –[i,g,e] och [a,r,k] är lika långa om [g,e] och [r,k] är lika långa –[g,e] och [r,k] är lika långa om [e] och [k] är lika långa –[e] och [k] är lika långa om [] och [] är lika långa –[] och [] är lika långa, eftersom tomma listan och tomma listan är lika långa.
13 lika_långa/2 forts Och så här fungerar det när prolog kommer fram till svaret för ?lika_långa(”sverige”,”norge”) : –[s,v,e,r,i,g,e] och [n,o,r,g,e] är lika långa om [v,e,r,i,g,e] och [o,r,g,e] är lika långa. –[v,e,r,i,g,e] och [o,r,g,e] är lika långa om [e,r,i,g,e] och [r,g,e] är lika långa –[e,r,i,g,e] och [r,g,e] är lika långa om [r,i,g,e] och [g,e] är lika långa –[r,i,g,e] och [g,e] är lika långa om [i,g,e] och [e] är lika långa –[i,g,e] och [e] är lika långa om [g,e] och [] är lika långa –[g,e] och [] är inte lika långa eftersom det inte finns någon klausul som matchar –Eftersom [g,e] och [] inte var lika långa så misslyckas anropet.
14 member/2 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). ?- member(e,"pelle"). yes ?- member(e,"lisa"). no
15 member/2 forts member/2 kan användas för att räkna upp alla element i en lista. ?- member(X,"pelle"). X = p ? ; X = e ? ; X = l ? ; X = e ? ; no
16 append/3 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).
17 append/3 forts append([],Xs,Xs). append([X|Xs],Ys,[X|Zs]) :- append(Xs,Ys,Zs). ?- append([1,2],[3],X). X = [1,2,3] ? ?- append("ja","ja",A),append(A,"men",B),append(B,"san",C). A = [j,a,j,a], B = [j,a,j,a,m,e,n], C = [j,a,j,a,m,e,n,s,a,n] ? yes
18 append/3 överkurs Man kan även använda append/3 till att dela upp en lista: ?- append(Xs,Ys,"lisa"). Xs = [], Ys = [l,i,s,a] ? ; Xs = [l], Ys = [i,s,a] ? ; Xs = [l,i], Ys = [s,a] ? ; Xs = [l,i,s], Ys = [a] ? ; Xs = [l,i,s,a], Ys = [] ? ; no