© Patrick Blackburn, Johan Bos & Kristina Striegnitz FL 5: Aritmetik Teori –Introducerar Prologs inbyggda operationer för aritmetik –Tillämpar dessa på enkla listhanteringsproblem, mha ackumulatorer –Ser på svansrekursiva predikat och förklarar varför de är mera effektiva än icke-svansrekursiva predikat
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Aritmetik i Prolog Prolog erbjuder ett antal grundläggande verktyg för aritmetik Heltal och flyttal = 5 3 x 4 = 12 5 – 3 = 2 3 – 5 = -2 4 2 = 2 1 är resten när 7 divideras med 2 ?- 5 is 2+3. ?- 12 is 3 4. ?- 2 is 5-3. ?- -2 is 3-5. ?- 2 is 4/2. ?- 1 is mod(7,2). AritmetikProlog
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Exempel på förfrågningar ?- 10 is 5+5. yes ?- 4 is 2+3. no ?- X is 3 4. X=12 yes ?- R is mod(7,2). R=1 yes
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Att definiera predikat mha aritmetik addThreeAndDouble(X, Y):- Y is (X+3) 2.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Att definiera predikat mha aritmetik addThreeAndDouble(X, Y):- Y is (X+3) 2. ?- addThreeAndDouble(1,X). X=8 yes ?- addThreeAndDouble(2,X). X=10 yes
© Patrick Blackburn, Johan Bos & Kristina Striegnitz En närmare titt Det är viktigt att veta att +, -, / och utför ingen aritmetik Uttryck som 3+2, 4-7, 5/5 är vanliga Prolog-termer –Funktor: +, -, /, –Aritet: 2 –Argument: heltal
© Patrick Blackburn, Johan Bos & Kristina Striegnitz En närmare titt ?- X =
© Patrick Blackburn, Johan Bos & Kristina Striegnitz En närmare titt ?- X = X = 3+2 yes ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz En närmare titt ?- X = X = 3+2 yes ? = X.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz En närmare titt ?- X = X = 3+2 yes ? = X. X = 3+2 yes ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Predikatet is/2 För att tvinga Prolog att verkligen evaluera aritmetiska uttryck, måste vi använda is såsom vi gjorde i exempelfallen Detta instruerar Prolog att utföra beräkningarna Eftersom detta inte är ett vanligt Prolog- predikat, finns det några begränsningar
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Predikatet is/2 ?- X is
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Predikatet is/2 ?- X is X = 5 yes ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Predikatet is/2 ?- X is X = 5 yes ? is X.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Predikatet is/2 ?- X is X = 5 yes ? is X. ERROR: is/2: Arguments are not sufficiently instantiated ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Predikatet is/2 ?- X is X = 5 yes ? is X. ERROR: is/2: Arguments are not sufficiently instantiated ?- Result is
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Predikatet is/2 ?- X is X = 5 yes ? is X. ERROR: is/2: Arguments are not sufficiently instantiated ?- Result is Result = 10 yes ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Begränsningar på användning av is/2 Vi får använda variabler på högra sidan av predikatet is Men när Prolog utför beräkningen måste variablerna vara instantierade med en variabelfri Prolog-term Denna Prolog-term måste vara ett aritmetiskt uttryck
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Notation Till slut två kommentarer på aritmetiska uttryck –3+2, 4/2, 4-5 är endast vanliga Prolog- termer i en användarvänlig notation: 3+2 är egentligen +(3,2) osv. –Även predikatet is är ett tvåställigt Prolog- predikat
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Notation Till slut två kommentarer på aritmetiska uttryck –3+2, 4/2, 4-5 är endast vanliga Prolog- termer i en användarvänlig notation: 3+2 är egentligen +(3,2) osv. –Även predikatet is är ett tvåställigt Prolog- predikat ?- is(X,+(3,2)). X = 5 yes
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Aritmetik och listor Hur lång är en lista? –Den tomma listan har längd 0 –En icke-tom lista har längd 1 plus längden av sin svans Försök formulera predikatet length!
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Längden av en lista i Prolog len([],0). len([_|L],N):- len(L,X), N is X + 1. ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Längden av en lista i Prolog len([],0). len([_|L],N):- len(L,X), N is X + 1. ?- len([a,b,c,d,e,[a,x],t],X).
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Längden av en lista i Prolog len([],0). len([_|L],N):- len(L,X), N is X + 1. ?- len([a,b,c,d,e,[a,x],t],X). X=7 yes ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Ackumulatorer Detta var ett rätt så bra program –Lätt att förstå –Relativt effektivt Men det finns en annan metod för att beräkna längden av en lista –Introducerar tanken bakom ackumulatorer –Ackumulatorer är variabler som innehåller mellanresultat
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Att definiera acclen/3 Predikatet acclen/3 har tre argument –Listan vars längd vi vill få reda på –Längden av listan, ett heltal –En ackumulator som håller reda på mellanresultat för längden
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Att definiera acclen/3 Ackumulatorn för acclen/3 –Startvärdet för ackumulatorn är 0 –Addera 1 till ackumulatorn för varje gång vi rekursivt behandlar huvudet av en lista –När vi når den tomma listan, innehåller ackumulatorn längden av listan Försök formulera acclen!
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Längden av en lista i Prolog acclen([],Acc,Length):- Length = Acc. acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length). ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Längden av en lista i Prolog acclen([],Acc,Length):- Length = Acc. acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length). ?- addera 1 till ackumulatorn varje gång vi avlägsnar huvudet från listan
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Längden av en lista i Prolog acclen([],Acc,Length):- Length = Acc. acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length). ?- När vi når den tomma listan, innehåller ackumulatorn listans längd
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Längden av en lista i Prolog acclen([],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length). ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Längden av en lista i Prolog acclen([],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length). ?-acclen([a,b,c],0,Len). Len=3 yes ?-
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för acclen/3 ?- acclen([a,b,c],0,Len). acclen([ ],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length).
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för acclen/3 ?- acclen([a,b,c],0,Len). / \ acclen([ ],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length).
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för acclen/3 ?- acclen([a,b,c],0,Len). / \ no ?- acclen([b,c],1,Len). / \ acclen([ ],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length).
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för acclen/3 ?- acclen([a,b,c],0,Len). / \ no ?- acclen([b,c],1,Len). / \ no ?- acclen([c],2,Len). / \ acclen([ ],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length).
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för acclen/3 ?- acclen([a,b,c],0,Len). / \ no ?- acclen([b,c],1,Len). / \ no ?- acclen([c],2,Len). / \ no ?- acclen([],3,Len). / \ acclen([ ],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length).
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för acclen/3 ?- acclen([a,b,c],0,Len). / \ no ?- acclen([b,c],1,Len). / \ no ?- acclen([c],2,Len). / \ no ?- acclen([],3,Len). / \ Len=3 no acclen([ ],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length).
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Att tillägga ett wrapper-predikat acclen([ ],Acc,Acc). acclen([ _|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length). length(List,Length):- acclen(List,0,Length). ?-length([a,b,c], X). X=3 yes
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Svansrekursion Varför är acclen/3 bättre än len/2 ? –acclen/3 är svansrekursiv medan len/2 inte är det Skillnaden: –När det gäller svansrekursiva predikat är resultatet färdigt beräknat så fort vi når basfallet –När det gäller rekursiva predikat som inte är svansrekursiva, finns det ännu mål att evaluera på stacken när vi når basfallet
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Jämförelse acclen([],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length). len([],0). len([_|L],NewLength):- len(L,Length), NewLength is Length + 1. Icke-svansrekursiv Svansrekursiv
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för len/2 ?- len([a,b,c], Len). len([],0). len([_|L],NewLength):- len(L,Length), NewLength is Length + 1.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för len/2 ?- len([a,b,c], Len). / \ no ?- len([b,c],Len1), Len is Len len([],0). len([_|L],NewLength):- len(L,Length), NewLength is Length + 1.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för len/2 ?- len([a,b,c], Len). / \ no ?- len([b,c],Len1), Len is Len / \ no ?- len([c], Len2), Len1 is Len2+1, Len is Len1+1. len([],0). len([_|L],NewLength):- len(L,Length), NewLength is Length + 1.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för len/2 ?- len([a,b,c], Len). / \ no ?- len([b,c],Len1), Len is Len / \ no ?- len([c], Len2), Len1 is Len2+1, Len is Len1+1. / \ no ?- len([], Len3), Len2 is Len3+1, Len1 is Len2+1, Len is Len len([],0). len([_|L],NewLength):- len(L,Length), NewLength is Length + 1.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för len/2 ?- len([a,b,c], Len). / \ no ?- len([b,c],Len1), Len is Len / \ no ?- len([c], Len2), Len1 is Len2+1, Len is Len1+1. / \ no ?- len([], Len3), Len2 is Len3+1, Len1 is Len2+1, Len is Len / \ Len3=0, Len2=1, no Len1=2, Len=3 len([],0). len([_|L],NewLength):- len(L,Length), NewLength is Length + 1.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sökträdet för acclen/3 ?- acclen([a,b,c],0,Len). / \ no ?- acclen([b,c],1,Len). / \ no ?- acclen([c],2,Len). / \ no ?- acclen([],3,Len). / \ Len=3 no acclen([ ],Acc,Acc). acclen([_|L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(L,NewAcc,Length).
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: X = 3*4. ?- X = 3*4. X = 3*4.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: X is 3*4. ?- X is 3*4. X = 12.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: 4 is X. ?- 4 is X. ERROR: is/2: Arguments are not sufficiently instantiated
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: X = Y. ?- X = Y. X = Y.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: 3 is 1+2. ?- 3 is 1+2. true.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: 3 is +(1,2). ?- 3 is +(1,2). true.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: 3 is X+2. ?- 3 is X+2. ERROR: is/2: Arguments are not sufficiently instantiated
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: X is 1+2. ?- X is 1+2. X = 3.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: 1+2 is 1+2. ?- 1+2 is 1+2. false. IS är inte unifierings- operator! Ej heller aritmetisk likhet!
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: is(X,+(1,2)). ?- is(X, +(1,2)). X = 3.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: 3+2 = +(3,2). ?- 3+2 = +(3,2). true.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: *(7,5) = 7*5. ?- *(7,5) = 7*5. true.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: *(7,+(3,2)) = 7*(3+2). ?- *(7, +(3,2)) = 7*(3+2). true.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: *(7,(3+2)) = 7*(3+2). ?- *(7,(3+2)) = 7*(3+2). true.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Vad svarar Prolog på: 7*3+2 = *(7,+(3,2)). ?- 7*3+2 = *(7,+(3,2)). false.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Definiera ett predikat increment/2 som kontrollerar att dess andra argument är ett större än dess första argument, ex. ?- increment(4,5). true. ?- increment(4,6). false. ?- increment(4,X). X = 5.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lite övningar... Definiera ett predikat increment/2 som kontrollerar att dess andra argument är ett större än dess första argument, ex. increment(B, A) :- A is B+1. Obs! ?- increment(X,5). ERROR: is/2: Arguments are not sufficiently instantiated
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Att jämföra heltal Några av Prologs aritmetiska predikat utför de facto beräkningarna själva Detta gäller de operatorer som jämför heltal
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Att jämföra heltal x < y x y x = y x y x y x > y X < Y X =< Y X =:= Y X =\= Y X >= Y X > Y AritmetikProlog Obs!
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Jämförelseoperatorer Har den sedvanliga betydelsen Påtvingar både det vänstra och det högra argumentet att evalueras ?- 2 < 4+1. yes ?- 4+3 > 5+5. no
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Jämförelseoperatorer ?- 4 = 4. yes ?- 2+2 = 4. no ?- 2+2 =:= 4. yes Har den sedvanliga betydelsen Påtvingar både det vänstra och det högra argumentet att evalueras Unifiering!!! Aritmetisk likhet
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Att jämföra tal Vi ska definiera ett predikat som tar två argument och gäller när: –Det första argumentet är en heltalslista –Det andra argumentet är det största heltalet i listan Grundidén –Vi ska använda en ackumulator –Ackumulatorn håller reda på det hittills största värdet –Om vi hittar ett större värde, uppdateras ackumulatorn
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Definition av accMax/3 accMax([H|T],A,Max):- H > A, accMax(T,H,Max). accMax([H|T],A,Max):- H =< A, accMax(T,A,Max). accMax([],A,A). ?- accMax([1,0,5,4],0,Max). Max=5 yes Fungerar ej för negativa tal!
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Att tillägga en wrapper max/2 accMax([H|T],A,Max):- H > A, accMax(T,H,Max). accMax([H|T],A,Max):- H =< A, accMax(T,A,Max). accMax([],A,A). max([H|T],Max):- accMax(T,H,Max). ?- max([1,0,5,4], Max). Max=5 yes ?- max([-3, -1, -5, -4], Max). Max= -1 yes ?- Fungerar detta för negativa tal?
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Sammandrag Vi har bekantat oss med aritmetik i Prolog Vi har sett på skillnaden mellan svansrekursiva och icke- svansrekursiva predikat Vi har introducerat programmerings- teknik som använder ackumulatorer Vi har också introducerat idén om wrapper-predikat