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
Aritmetik i Prolog Prolog erbjuder ett antal grundläggande verktyg för aritmetik Heltal och flyttal Aritmetik 2 + 3 = 5 3 x 4 = 12 5 3 = 2 3 5 = -2 4 : 2 = 2 1 är resten när 7 divideras med 2 Prolog?- 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).
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
Att definiera predikat mha aritmetik addthreeanddouble(x, Y):- Y is (X+3) * 2.
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
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
En närmare titt?- X = 3 + 2.
En närmare titt?- X = 3 + 2. X = 3+2 yes?-
En närmare titt?- X = 3 + 2. X = 3+2 yes?- 3 + 2 = X.
En närmare titt?- X = 3 + 2. X = 3+2 yes?- 3 + 2 = X. X = 3+2 yes?-
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 Prologpredikat, finns det några begränsningar
Predikatet is/2?- X is 3 + 2.
Predikatet is/2?- X is 3 + 2. X = 5 yes?-
Predikatet is/2?- X is 3 + 2. X = 5 yes?- 3 + 2 is X.
Predikatet is/2?- X is 3 + 2. X = 5 yes?- 3 + 2 is X. ERROR: is/2: Arguments are not sufficiently instantiated?-
Predikatet is/2?- X is 3 + 2. X = 5 yes?- 3 + 2 is X. ERROR: is/2: Arguments are not sufficiently instantiated?- Result is 2+2+2+2+2.
Predikatet is/2?- X is 3 + 2. X = 5 yes?- 3 + 2 is X. ERROR: is/2: Arguments are not sufficiently instantiated?- Result is 2+2+2+2+2. Result = 10 yes?-
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
Notation Till slut två kommentarer på aritmetiska uttryck 3+2, 4/2, 4-5 är endast vanliga Prologtermer i en användarvänlig notation: 3+2 är egentligen +(3,2) osv. Även predikatet is är ett tvåställigt Prologpredikat
Notation Till slut två kommentarer på aritmetiska uttryck 3+2, 4/2, 4-5 är endast vanliga Prologtermer i en användarvänlig notation: 3+2 är egentligen +(3,2) osv. Även predikatet is är ett tvåställigt Prologpredikat?- is(x,+(3,2)). X = 5 yes
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!
Längden av en lista i Prolog len([],0). len([_ L],N):- len(l,x), N is X + 1.?-
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).
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?-
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
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
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!
Längden av en lista i Prolog acclen([],acc,length):- Length = Acc. acclen([_ L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(l,newacc,length).?-
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
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
Längden av en lista i Prolog acclen([],acc,acc). acclen([_ L],OldAcc,Length):-?- NewAcc is OldAcc + 1, acclen(l,newacc,length).
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?-
Sökträdet för acclen/3 acclen([ ],Acc,Acc).?- acclen([a,b,c],0,len). acclen([_ L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(l,newacc,length).
Sökträdet för acclen/3 acclen([ ],Acc,Acc).?- acclen([a,b,c],0,len). / \ acclen([_ L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(l,newacc,length).
Sökträdet för acclen/3 acclen([ ],Acc,Acc).?- acclen([a,b,c],0,len). / \ no?- acclen([b,c],1,len). / \ acclen([_ L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(l,newacc,length).
Sökträdet för acclen/3 acclen([ ],Acc,Acc).?- acclen([a,b,c],0,len). / \ no?- acclen([b,c],1,len). / \ no?- acclen([c],2,len). / \ acclen([_ L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(l,newacc,length).
Sökträdet för acclen/3 acclen([ ],Acc,Acc).?- acclen([a,b,c],0,len). / \ no?- acclen([b,c],1,len). / \ no?- acclen([c],2,len). no / \ acclen([_ L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(l,newacc,length).?- acclen([],3,len). / \
Sökträdet för acclen/3 acclen([ ],Acc,Acc).?- acclen([a,b,c],0,len). / \ no?- acclen([b,c],1,len). / \ no?- acclen([c],2,len). no / \?- acclen([],3,len). / \ Len=3 acclen([_ L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(l,newacc,length). no
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
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
Jämförelse Icke-svansrekursiv Svansrekursiv len([],0). len([_ L],NewLength):- len(l,length), NewLength is Length + 1. acclen([],acc,acc). acclen([_ L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(l,newacc,length).
Sökträdet för len/2?- len([a,b,c], Len). len([],0). len([_ L],NewLength):- len(l,length), NewLength is Length + 1.
Sökträdet för len/2?- len([a,b,c], Len). no / \?- len([b,c],len1), Len is Len1 + 1. len([],0). len([_ L],NewLength):- len(l,length), NewLength is Length + 1.
Sökträdet för len/2?- len([a,b,c], Len). no / \?- len([b,c],len1), Len is Len1 + 1. / \ no?- len([c], Len2), Len1 is Len2+1, Len is Len1+1. len([],0). len([_ L],NewLength):- len(l,length), NewLength is Length + 1.
Sökträdet för len/2?- len([a,b,c], Len). no / \?- len([b,c],len1), Len is Len1 + 1. / \ 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 Len1 + 1. len([],0). len([_ L],NewLength):- len(l,length), NewLength is Length + 1.
Sökträdet för len/2?- len([a,b,c], Len). / \ no?- len([b,c],len1), Len is Len1 + 1. / \ no?- len([c], Len2), Len1 is Len2+1, Len is Len1+1. / \ no Len3=0, Len2=1, Len1=2, Len=3?- len([], Len3), Len2 is Len3+1, Len1 is Len2+1, Len is Len1 + 1. / \ len([],0). len([_ L],NewLength):- len(l,length), NewLength is Length + 1. no
Sökträdet för acclen/3 acclen([ ],Acc,Acc).?- acclen([a,b,c],0,len). / \ no?- acclen([b,c],1,len). / \ no?- acclen([c],2,len). no / \?- acclen([],3,len). / \ Len=3 acclen([_ L],OldAcc,Length):- NewAcc is OldAcc + 1, acclen(l,newacc,length). no
Lite övningar... Vad svarar Prolog på: X = 3*4.?- X = 3*4. X = 3*4.
Lite övningar... Vad svarar Prolog på: X is 3*4.?- X is 3*4. X = 12.
Lite övningar... Vad svarar Prolog på: 4 is X.?- 4 is X. ERROR: is/2: Arguments are not sufficiently instantiated
Lite övningar... Vad svarar Prolog på: X = Y.?- X = Y. X = Y.
Lite övningar... Vad svarar Prolog på: 3 is 1+2.?- 3 is 1+2. true.
Lite övningar... Vad svarar Prolog på: 3 is +(1,2).?- 3 is +(1,2). true.
Lite övningar... Vad svarar Prolog på: 3 is X+2.?- 3 is X+2. ERROR: is/2: Arguments are not sufficiently instantiated
Lite övningar... Vad svarar Prolog på: X is 1+2.?- X is 1+2. X = 3.
Lite övningar... Vad svarar Prolog på: 1+2 is 1+2.?- 1+2 is 1+2. false. Ej heller aritmetisk likhet! IS är inte unifieringsoperator!
Lite övningar... Vad svarar Prolog på: is(x,+(1,2)).?- is(x, +(1,2)). X = 3.
Lite övningar... Vad svarar Prolog på: 3+2 = +(3,2).?- 3+2 = +(3,2). true.
Lite övningar... Vad svarar Prolog på: *(7,5) = 7*5.?- *(7,5) = 7*5. true.
Lite övningar... Vad svarar Prolog på: *(7,+(3,2)) = 7*(3+2).?- *(7, +(3,2)) = 7*(3+2). true.
Lite övningar... Vad svarar Prolog på: *(7,(3+2)) = 7*(3+2).?- *(7,(3+2)) = 7*(3+2). true.
Lite övningar... Vad svarar Prolog på: 7*3+2 = *(7,+(3,2)).?- 7*3+2 = *(7,+(3,2)). false.
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.
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
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
Att jämföra heltal Aritmetik Prolog x < y X < Y x y x = y x y x y x > y X =< Y X =:= Y X =\= Y X >= Y X > Y Obs!
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
Jämförelseoperatorer Har den sedvanliga betydelsen Påtvingar både det vänstra och det högra argumentet att evalueras?- 4 = 4. yes?- 2+2 = 4. no?- 2+2 =:= 4. yes Unifiering!!! Aritmetisk likhet
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
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!
Att tillägga en wrapper max/2 accmax([h T],A,Max):- H > A, accmax(t,h,max).?- max([1,0,5,4], Max). Max=5 yes accmax([h T],A,Max):- H =< A, accmax(t,a,max). accmax([],a,a). max([h T],Max):- accmax(t,h,max).?- max([-3, -1, -5, -4], Max). Max= -1 yes?- Fungerar detta för negativa tal?
Sammandrag Vi har bekantat oss med aritmetik i Prolog Vi har sett på skillnaden mellan svansrekursiva och ickesvansrekursiva predikat Vi har introducerat programmeringsteknik som använder ackumulatorer Vi har också introducerat idén om wrapper-predikat