Presentation laddar. Vänta.

Presentation laddar. Vänta.

© Patrick Blackburn, Johan Bos & Kristina Striegnitz FL 4: Listor (kap. 4 & 6) Teori –Introducera listor, en viktig rekursiv datastruktur som ofta används.

Liknande presentationer


En presentation över ämnet: "© Patrick Blackburn, Johan Bos & Kristina Striegnitz FL 4: Listor (kap. 4 & 6) Teori –Introducera listor, en viktig rekursiv datastruktur som ofta används."— Presentationens avskrift:

1 © Patrick Blackburn, Johan Bos & Kristina Striegnitz FL 4: Listor (kap. 4 & 6) Teori –Introducera listor, en viktig rekursiv datastruktur som ofta används inom Prolog-programmering –Definiera predikatet member/2, ett basverktyg för listhantering –Illustrera idén om hur man bearbetar listorna rekursivt.

2 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Listor En lista är en ändlig sekvens av element Exempel på listor i Prolog: [mia, vincent, jules, yolanda] [mia, robber(honeybunny), X, 2, mia] [ ] [mia, [vincent, jules], [butch, friend(butch)]] [[ ], dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]]

3 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Viktigt om listor Listelementen innesluts i hakparenteser Längden av en lista är antalet element i den Alla sorter av Prolog-termer kan utgöra listelement, också i en och samma lista! Det finns en speciell lista: tomma listan [ ]

4 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail En icke-tom lista kan tänkas bestå av två delar –listhuvud (head) –svansen (tail) Huvudet är listans första element Svansen är resten av listan –Svansen är det som återstår när vi avlägsnar det första elementet –Svansen av en lista är alltid en lista

5 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail exempel 1 [mia, vincent, jules, yolanda] Head: Tail:

6 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail exempel 1 [mia, vincent, jules, yolanda] Head: mia Tail:

7 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail exempel 1 [mia, vincent, jules, yolanda] Head: mia Tail: [vincent, jules, yolanda]

8 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail exempel 2 [[ ], dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]] Head: Tail:

9 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail exempel 2 [[ ], dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]] Head: [ ] Tail:

10 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail exempel 2 [[ ], dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]] Head: [ ] Tail: [dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]]

11 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail exempel 3 [dead(z)] Head: Tail:

12 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail exempel 3 [dead(z)] Head: dead(z) Tail:

13 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och Tail exempel 3 [dead(z)] Head: dead(z) Tail: [ ]

14 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Head och tail av tom lista Den tomma listan har varken huvud eller svans För Prolog är [ ] en speciell, enkel lista utan struktur Den tomma listan spelar en viktig roll för rekursiva predikat för listhantering i Prolog

15 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Inbyggd operator | Prolog har en speciell inbyggd operator | som kan användas för att dekonstruera en lista i head och tail. |-operatorn är ett centralt verktyg när det gäller att skriva kod för listmanipulering

16 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Inbyggd operator | ?- [Head|Tail] = [mia, vincent, jules, yolanda]. Head = mia Tail = [vincent,jules,yolanda] yes ?-

17 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Inbyggd operator | ?- [X|Y] = [mia, vincent, jules, yolanda]. X = mia Y = [vincent,jules,yolanda] yes ?-

18 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Inbyggd operator | ?- [X|Y] = [ ]. no ?-

19 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Inbyggd operator | ?- [X,Y|Tail] = [[ ], dead(z), [2, [b,c]], [], Z, [2, [b,c]]]. X = [ ] Y = dead(z) Z = _4543 Tail = [[2, [b,c]], [ ], Z, [2, [b,c]]] yes ?-

20 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Anonym variabel Anta att vi är intresserade av listans andra och fjärde element ?- [X1,X2,X3,X4|Tail] = [mia, vincent, marsellus, jody, yolanda]. X1 = mia X2 = vincent X3 = marsellus X4 = jody Tail = [yolanda] yes ?-

21 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Anonyma variabler Det finns ett enklare sätt att få bara den information vi är intresserade av: ?- [ _,X2, _,X4|_ ] = [mia, vincent, marsellus, jody, yolanda]. X2 = vincent X4 = jody yes ?- Understrecket är den anonyma variabeln

22 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Den anonyma variabeln Används när du behöver en variabel, men är inte intresserad av vad den instantieras till Varje instans av den anonyma variabeln är oberoende, dvs de kan instantieras till olika termer i samma mönster

23 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Member En av de mest grundläggande saker när det gäller listhantering är att veta om ett element är medlem i en lista eller ej Så nu gäller det att skriva ett predikat som, givet en term X och en lista L, berättar ifall X hör till L Detta predikat brukar kallas för member/2

24 © Patrick Blackburn, Johan Bos & Kristina Striegnitz member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?-

25 © Patrick Blackburn, Johan Bos & Kristina Striegnitz member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(yolanda,[yolanda,trudy,vincent,jules]).

26 © Patrick Blackburn, Johan Bos & Kristina Striegnitz member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(yolanda,[yolanda,trudy,vincent,jules]). yes ?-

27 © Patrick Blackburn, Johan Bos & Kristina Striegnitz member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(vincent,[yolanda,trudy,vincent,jules]).

28 © Patrick Blackburn, Johan Bos & Kristina Striegnitz member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(vincent,[yolanda,trudy,vincent,jules]). yes ?-

29 © Patrick Blackburn, Johan Bos & Kristina Striegnitz member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(zed,[yolanda,trudy,vincent,jules]).

30 © Patrick Blackburn, Johan Bos & Kristina Striegnitz member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(zed,[yolanda,trudy,vincent,jules]). no ?-

31 © Patrick Blackburn, Johan Bos & Kristina Striegnitz member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(X,[yolanda,trudy,vincent,jules]).

32 © Patrick Blackburn, Johan Bos & Kristina Striegnitz member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(X,[yolanda,trudy,vincent,jules]). X = yolanda; X = trudy; X = vincent; X = jules; no

33 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Att omskriva member/2 member(X,[X|_]). member(X,[_|T]):- member(X,T).

34 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Att bearbeta listorna rekursivt Predikatet member/2 jobbar genom att rekursivt arbeta längs listan –Det gör något med listhuvudet och sedan –... gör det samma sak rekursivt med svansen Den här tekniken är central för Prolog och därför är den viktig att behärska

35 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exempel: a2b/2 Predikatet a2b/2 tar två listor som argument och lyckas –om det första argumentet är en lista av a:n, och –det andra argumentet är en lika lång lista av b:n ?- a2b([a,a,a,a],[b,b,b,b]). yes ?- a2b([a,a,a,a],[b,b,b]). no ?- a2b([a,c,a,a],[b,b,b,t]). no

36 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Definiera a2b/2: steg 1 Ofta är det bästa sättet att lösa dylika problem att tänka på det enklaste fallet Här innebär detta den tomma listan a2b([],[]).

37 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Definiera a2b/2: steg 2 Nu gäller det att tänka rekursivt! När borde a2b/2 bestämma att två icke- tomma listor är en lista av a:n och en lista av b:n av exakt samma längd? a2b([],[]). a2b([a|L1],[b|L2]):- a2b(L1,L2).

38 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Testa a2b/2 a2b([],[]). a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b([a,a,a],[b,b,b]). yes ?-

39 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Testa a2b/2 a2b([],[]). a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b([a,a,a,a],[b,b,b]). no ?-

40 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Testa a2b/2 a2b([],[]). a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b([a,t,a,a],[b,b,b,c]). no ?-

41 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Studera a2b/2 vidare... a2b([],[]). a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b([a,a,a,a,a], X). X = [b,b,b,b,b] yes ?-

42 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Studera a2b/2 vidare... a2b([],[]). a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b(X,[b,b,b,b,b,b,b]). X = [a,a,a,a,a,a,a] yes ?-

43 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Denna FL hittills... Vi har introducerat listor och rekursiva predikat som bearbetar listor Denna typ av programmering är fundamental för Prolog De flesta predikat du kommer att skriva när du jobbar med Prolog kommer att vara varianter av dessa predikat

44 © Patrick Blackburn, Johan Bos & Kristina Striegnitz FL fortsätter: mera listor Teori –Definiera append/3, ett predikat för att sammanfoga två listor, och visa vad som kan göras med det –Diskutera två sätt att reversera en lista Ett naivt sätt mha append/3 Ett mera effektivt sätt mha ackumulatorer

45 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Append Nu gäller det att definiera det viktiga predikatet append/3 vars argument är alla listor Deklarativt gäller append(L1,L2,L3) om listan L3 är resultatet av att sammanfoga listorna L1 och L2 ?- append([a,b,c,d],[3,4,5],[a,b,c,d,3,4,5]). yes ?- append([a,b,c],[3,4,5],[a,b,c,d,3,4,5]). no

46 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Append proceduralt sett Från ett proceduralt perspektiv är den mest självklara användningen av append/3 att sammanfoga två listor Vi kan göra detta enkelt genom att använda en variabel som tredje argument ?- append([a,b,c,d],[1,2,3,4,5], X). X=[a,b,c,d,1,2,3,4,5] yes ?- Kom ihåg att elementen INTE behöver ha samma datatyp!

47 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Definition av append/3 Rekursiv definition –Basfallet: att sammanfoga den tomma listan till vilken lista som helst producerar samma lista –Det rekursiva steget säger att när man sammanfogar en icke-tom lista [H|T] med en lista L, blir resultatet en lista med huvudet H och resultatet av att sammanfoga T med L append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

48 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Hur append/3 fungerar Två sätt att ta reda på detta: –Använd trace/0 på några exempel –Rita sökträdet! ?- append([a,b,c],[1,2,3], R).

49 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

50 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

51 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

52 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

53 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

54 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

55 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ † L1=[c|L2] ?- append([],[1,2,3],L2) append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

56 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ † L1=[c|L2] ?- append([],[1,2,3],L2) / \ append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

57 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ † L1=[c|L2] ?- append([],[1,2,3],L2) / \ L2=[1,2,3] † append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3). R1 matchar nu vårt mönster,så vi når basfallet. R2 gäller ej längre.

58 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ † L1=[c|L2] ?- append([],[1,2,3],L2) / \ L2=[1,2,3] † L2=[1,2,3] L1=[c|L2]=[c,1,2,3] L0=[b|L1]=[b,c,1,2,3] R=[a|L0]=[a,b,c,1,2,3] append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

59 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3], [c|1,2,3]) / \ † L1=[c|1,2,3] ?- append([],[1,2,3], [1,2,3]) / \ L2=[1,2,3] † L2=[1,2,3] L1=[c|L2]=[c,1,2,3] L0=[b|L1]=[b,c,1,2,3] R=[a|L0]=[a,b,c,1,2,3] append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

60 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], R). / \ † R = [a|L0] ?- append([b,c],[1,2,3], [b|c,1,2,3]) / \ † L0=[b|c,1,2,3] ?- append([c],[1,2,3], [c|1,2,3]) / \ † L1=[c|1,2,3] ?- append([],[1,2,3], [1,2,3]) / \ L2=[1,2,3] † L2=[1,2,3] L1=[c|L2]=[c,1,2,3] L0=[b|L1]=[b,c,1,2,3] R=[a|L0]=[a,b,c,1,2,3] append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

61 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Exemplet med sökträd ?- append([a,b,c],[1,2,3], [a,b,c,1,2,3] ). / \ † R = [a|b,c,1,2,3] ?- append([b,c],[1,2,3], [b,c,1,2,3]) / \ † L0=[b|c,1,2,3] ?- append([c],[1,2,3], [c|1,2,3]) / \ † L1=[c|1,2,3] ?- append([],[1,2,3], [1,2,3]) / \ L2=[1,2,3] † L2=[1,2,3] L1=[c|L2]=[c,1,2,3] L0=[b|L1]=[b,c,1,2,3] R=[a|L0]=[a,b,c,1,2,3] append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

62 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Att använda append/3 Nu när vi vet hur append/3 fungerar ska vi se på några tillämpningar Att dela en lista: ?- append(X,Y, [a,b,c,d]). X=[ ] Y=[a,b,c,d]; X=[a] Y=[b,c,d]; X=[a,b] Y=[c,d]; X=[a,b,c] Y=[d]; X=[a,b,c,d] Y=[ ]; no

63 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Prefix och suffix Vi kan också använda append/3 för att definiera andra nyttiga predikat Ett bra exempel är att hitta prefixen (dellistor i början) och suffixen (dellistor i slutet) av en lista

64 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Definition av prefix/2 En lista P är ett prefix av någon lista L när det existerar någon sådan lista att L utgör resultatet av att sammanfoga P med denna lista. Vi använder oss av den anonyma variabeln eftersom vi inte bryr oss om den andra listan prefix(P,L):- append(P,_,L).

65 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Att använda prefix/2 prefix(P,L):- append(P,_,L). ?- prefix(X, [a,b,c,d]). X=[ ]; X=[a]; X=[a,b]; X=[a,b,c]; X=[a,b,c,d]; no

66 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Definition av suffix/2 En lista S är ett suffix av någon lista L när det existerar någon sådan lista att L utgör resultatet av att sammanfoga denna lista med S. Vi använder oss igen av den anonyma variabeln, eftersom vi inte bryr oss om denna andra lista. suffix(S,L):- append(_,S,L).

67 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Att använda suffix/2 suffix(S,L):- append(_,S,L). ?- suffix(X, [a,b,c,d]). X=[a,b,c,d]; X=[b,c,d]; X=[c,d]; X=[d]; X=[]; no

68 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Definition av sublist/2 Nu är det enkelt att skriva ett predikat som hittar dellistorna av en lista Dellistorna av en lista L är helt enkelt prefixen av suffixen av L sublist(Sub,List):- suffix(Suffix,List), prefix(Sub,Suffix). Alternativt: suffixen av prefixen av L

69 Testkörning... © Patrick Blackburn, Johan Bos & Kristina Striegnitz ?- listing. prefix(A, B) :- append(A, _, B). sublist(B, A) :- suffix(C, A), prefix(B, C). suffix(A, B) :- append(_, A, B). true. prefixen av suffixen av lista A...

70 Testkörning... © Patrick Blackburn, Johan Bos & Kristina Striegnitz ?- sublist(Sub, [a,b,c,d,e]). Sub = [] ; Sub = [a] ; Sub = [a, b] ; Sub = [a, b, c] ; Sub = [a, b, c, d] ; Sub = [a, b, c, d, e] ; Sub = [] ; Sub = [b] ; Sub = [b, c] ; Sub = [b, c, d] ; Sub = [b, c, d, e] ; Sub = [] ; Sub = [c] ; Sub = [c, d] ; Sub = [c, d, e] ; Sub = [] ; Sub = [d] ; Sub = [d, e] ; Sub = [] ; Sub = [e] ; Sub = [] ; false. prefixen av suffixen av lista A... suffix [a,b,c,d,e] suffix [b,c,d,e] suffix [c,d,e] suffix [d,e] suffix [e] suffix []

71 Testkörning... © Patrick Blackburn, Johan Bos & Kristina Striegnitz ?- listing. prefix(A, B) :- append(A, _, B). sublist(B, A) :- prefix(C, A), suffix(B, C). suffix(A, B) :- append(_, A, B). true. suffixen av prefixen av lista A...

72 Testkörning... © Patrick Blackburn, Johan Bos & Kristina Striegnitz ?- sublist(Sub, [a,b,c,d,e]). Sub = [] ; Sub = [a] ; Sub = [] ; Sub = [a, b] ; Sub = [b] ; Sub = [] ; Sub = [a, b, c] ; Sub = [b, c] ; Sub = [c] ; Sub = [] ; Sub = [a, b, c, d] ; Sub = [b, c, d] ; Sub = [c, d] ; Sub = [d] ; Sub = [] ; Sub = [a, b, c, d, e] ; Sub = [b, c, d, e] ; Sub = [c, d, e] ; Sub = [d, e] ; Sub = [e] ; Sub = [] ; false. prefix [a,b,c,d,e] prefix [a,b,c,d] prefix [a,b,c] prefix [a,b] prefix [a] prefix [] suffixen av prefixen av lista A...

73 © Patrick Blackburn, Johan Bos & Kristina Striegnitz append/3 och effektivitet Predikatet append/3 är nyttigt, och det är viktigt att känna till hur det ska användas Det är lika viktigt att veta att append/3 kan leda till mycket ineffektiva program Varför? –Att sammanfoga en lista görs inte som en enda handling... –... utan genom att traversera längs den ena listan

74 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Fråga Vi skulle vilja sammanfoga två listor mha append/3 –List 1: [a,b,c,d,e,f,g,h,i] –List 2: [j,k,l] Resultatet borde vara en lista med alla elementen från List 1 och List 2, men elementens ordning spelar ingen roll Vilketdera av de följande målen är det mest effektiva sättet att sammafoga listorna? ?- append([a,b,c,d,e,f,g,h,i],[j,k,l],R). ?- append([j,k,l],[a,b,c,d,e,f,g,h,i],R). append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

75 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Svaret Se hur append/3 är definierat Det jobbar längs det första argumentet och rör egentligen inte alls den andra listan Detta innebär att det lönar sig att anropa det med den kortare listan som första argument Naturligtvis vet man inte alltid vilkendera listan som är kortare, och man kan bara göra detta när elementens ordning i resultatlistan inte spelar någon roll. Men om denna princip går att tillämpa, blir programmet mera effektivt append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

76 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Att reversera en lista Vi ska exemplifiera problemet med append/3 genom att använda det för att reversera en lista Vi ska alltså definiera ett predikat som omvandlar listan [a,b,c,d,e] till lista [e,d,c,b,a] Detta kan vara ett nyttigt verktyg att ha, eftersom Prolog endast erbjuder lätt access till listans första element

77 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Naiv reverse Rekursiv definition 1.Om vi reverserar den tomma listan, får vi den tomma listan 2.Om vi reverserar listan [H|T], får vi den lista som är reversen av T sammanfogad med lista [H] För att se att denna definition är korrekt, betrakta listan [a,b,c,d]. –Om vi reverserar svansen av denna lista, får vi[d,c,b]. –Att sammanfoga denna med [a] ger [d,c,b,a]

78 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Naiv reverse i Prolog Den här definitionen är korrekt, men den innebär en massa arbete! Största delen av tiden går åt att utföra appends Men det finns ett bättre sätt … naiveReverse([],[]). naiveReverse([H|T],R):- naiveReverse(T,RT), append(RT,[H],R).

79 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Reverse mha en ackumulator Det bättre sättet använder en ackumulator Ackumulatorn kommer att vara en lista som är tom när vi börjar reversera Vi tar helt enkelt huvudet av listan vi vill reversera och sätter det som huvud till ackumulatorn (sista element i vår lista blir först i ackumulatorn) Vi fortsätter tills vi når [ ]. Vid detta skede kommer ackumulatorn att innehålla reversen av vår lista

80 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Reverse mha en ackumulator accReverse([ ],L,L). accReverse([H|T],Acc,Rev):- accReverse(T,[H|Acc],Rev).

81 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Reverse mha en ackumulator accReverse([ ],L,L). accReverse([H|T],Acc,Rev):- accReverse(T,[H|Acc],Rev). accReverse gäller mellan lista [H|T], Acc och Rev om accReverse gäller mellan T, [H|Acc] och Rev

82 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Reverse mha en ackumulator accReverse([ ],L,L). accReverse([H|T],Acc,Rev):- accReverse(T,[H|Acc],Rev). accReverse([1,2,3,4], [], R) :- accReverse([2,3,4], [1|[]], R) accReverse([2,3,4], [1], R) :- accReverse([3,4], [2|1], R) accReverse([3,4], [2,1], R) :- accReverse([4], [3|2,1], R) accReverse([4], [3,2,1], R) :- accReverse([], [4|3,2,1], R) accReverse([], [4,3,2,1], R) basfallet!

83 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Att tillägga ett “wrapper”- predikat accReverse([ ],L,L). accReverse([H|T],Acc,Rev):- accReverse(T,[H|Acc],Rev). reverse(L1,L2):- accReverse(L1,[ ],L2). Gömmer det ackumulativa hjälp- predikatet

84 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Så här fungerar ackumulatorn List: [a,b,c,d]Ackumulator: []

85 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Så här fungerar ackumulatorn List: [a,b,c,d] List: [b,c,d] Ackumulator: [] Ackumulator: [a]

86 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Så här fungerar ackumulatorn List: [a,b,c,d] List: [b,c,d] List: [c,d] Ackumulator: [] Ackumulator: [a] Ackumulator: [b,a]

87 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Så här fungerar ackumulatorn List: [a,b,c,d] List: [b,c,d] List: [c,d] List: [d] Ackumulator: [] Ackumulator: [a] Ackumulator: [b,a] Ackumulator: [c,b,a]

88 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Så här fungerar ackumulatorn List: [a,b,c,d] List: [b,c,d] List: [c,d] List: [d] List: [] Ackumulator: [] Ackumulator: [a] Ackumulator: [b,a] Ackumulator: [c,b,a] Ackumulator: [d,c,b,a]

89 Listor i användning © Patrick Blackburn, Johan Bos & Kristina Striegnitz Problemlösning i Prolog! Farmaren, vargen, geten och kålhuvudet

90 Materialet från George F. Luger & William A. Stubblefield: Artificial Intelligence: Structures and Strategies for Complex Problem Solving © Patrick Blackburn, Johan Bos & Kristina Striegnitz

91 Farmaren, vargen, geten och kålhuvudet Farmaren, hans varg, get och ett kålhuvud ska över en flod med en robåt. Båten kan bära farmaren och en annan. Bara farmaren kan ro. Om vargen lämnas ensam (utan den övervakande farmaren) med geten, äter vargen upp geten. Om geten lämnas ensam (utan den övervakande farmaren) med kålhuvudet, äter geten upp kålhuvudet. Hur ska alla komma oskadda över floden? © Patrick Blackburn, Johan Bos & Kristina Striegnitz

92 Farmaren, vargen, geten och kålhuvudet Modellera tillstånd: En fyrtupel state(farmer, wolf, goat, cabbage) ska representera deltagarna. Vi antar att floden ska korsas från väst (w) till öst (e) (eller tvärtom). Då visar vi var alla deltagarna befinner sig med fyrtupeln ovan, ex. state(w, w, w, w). © Patrick Blackburn, Johan Bos & Kristina Striegnitz farmer wolf goat cabbage

93 Modellera tillstånd © Patrick Blackburn, Johan Bos & Kristina Striegnitz Startläget är state(w, w, w, w). Slutläget ska vara state(e, e, e, e). Hur kommer vi från startläget till slutläget?

94 Modellera tillstånd © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) Startläget är state(w, w, w, w). Slutläget ska vara state(e, e, e, e). För att tillståndet state ska ändras, ska farmaren byta sida från w till e eller tvärtom. Utöver farmarens byte får högst en annan byta sida (bara farmaren kan ro!). Förbjudna states: state(w, e, e, _) (Vargen och geten tillsammans utan farmaren) state(e, w, w, _) (Vargen och geten tillsammans utan farmaren) state(w, _, e, e) (Geten och kålhuvudet tillsammans utan farmaren) state(e, _, w, w) (Geten och kålhuvudet tillsammans utan farmaren)

95 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) opp(e, w). opp(w, e). unsafe(state(X, Y, Y, C) :- opp(X, Y). unsafe(state(X, W, Y, Y) :- opp(X, Y). move(state(X,X,G,C), state(Y,Y,G,C)) :- opp(X,Y), not(unsafe(state(Y,Y,G,C))), writelist(['try farmer takes wolf',Y,Y,G,C]).

96 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) move(state(X,W,X,C), state(Y,W,Y,C)) :- opp(X,Y), not(unsafe(state(Y,W,Y,C))), writelist(['try farmer takes goat',Y,W,Y,C]). move(state(X,W,G,X), state(Y,W,G,Y)) :- opp(X,Y), not(unsafe(state(Y,W,G,Y))), writelist(['try farmer takes cabbage',Y,W,G,Y]).

97 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) move(state(X,W,G,C), state(Y,W,G,C)) :- opp(X,Y), not(unsafe(state(Y,W,G,C))), writelist(['try farmer takes self',Y,W,G,C]). move(state(F,W,G,C), state(F,W,G,C)) :- writelist([' BACKTRACK from:',F,W,G,C]), fail. Vi registrerar en dead end

98 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) writelist([]) :- nl. writelist([H|T]) :- print(H), tab(1), /* "tab(n)" skips n spaces. */ writelist(T).

99 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) Hur hindra farmaren från att ro fram och tillbaka utan att han kommer närmare sitt mål? Samma problem som loopar i en graf! Vi måste hålla reda på de tillstånd där vi redan varit. För detta ändamål måste vi ha en stack.

100 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) ~/prolog]$ more adt.pl /* ADT by Luger & Stubblefield */ member(X, [X|_]). member(X, [_|T]) :- member(X, T). empty_stack([]). member_stack(E, S) :- member(E, S). % tests if an element is a member % of the stack

101 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) stack(E, S, [E|S]). % push: ?- stack(a, [b, c, d], S). % S = [a, b, c, d]. % pop: stack(Top, Rest, [a, b, c]). % Top = a, Rest = [b, c]. % peek at the top element: % ?- stack(Top, _, [a, b, c]). % Top = a

102 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) reverse_print_stack(S) :- empty_stack(S). reverse_print_stack(S) :- stack(E, Rest, S), reverse_print_stack(Rest), write(E), nl. Tillstånden lagras på stacken. Genom att printa stackinnehållet i motsatt ordning får vi den rätta sekvensen som farmaren ska följa.

103 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) path(Goal, Goal, Been_stack) :- write('Solution Path Is:' ), nl, reverse_print_stack(Been_stack). path(State, Goal, Been_stack) :- move(State, Next_state), not(member_stack(Next_state, Been_stack)), stack(Next_state, Been_stack, New_been_stack), path(Next_state, Goal, New_been_stack), !. Been_stack håller reda på tillstånd där vi redan varit push Existerar stigen? cut!

104 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) path(Goal, Goal, Been_stack) :- write('Solution Path Is:' ), nl, reverse_print_stack(Been_stack). path(State, Goal, Been_stack) :- move(State, Next_state), not(member_stack(Next_state, Been_stack)), stack(Next_state, Been_stack, New_been_stack), path(Next_state, Goal, New_been_stack), !. cut! cut gör att vi inte söker efter alter- nativa bevis

105 Modellera förflyttning © Patrick Blackburn, Johan Bos & Kristina Striegnitz state(farmer, wolf, goat, cabbage) go(Start, Goal) :- empty_stack(Empty_been_stack), stack(Start, Empty_been_stack, Been_stack), path(Start, Goal, Been_stack). / * Run this code by giving PROLOG a "go" goal. * For example, to find a path from the west bank to the east bank, * give PROLOG the query: * * go(state(w,w,w,w), state(e,e,e,e)). */

106 Körning © Patrick Blackburn, Johan Bos & Kristina Striegnitz ?- go(state(w,w,w,w), state(e,e,e,e)). try farmer takes goat e w e w % från w w w w try farmer takes goat w w w w % misslyckas, pröva try farmer takes self w w e w % detta från e w e w try farmer takes wolf e e e w % från föreg. try farmer takes wolf w w e w % från föreg. try farmer takes goat w e w w % från e e e w try farmer takes goat e e e w % från föreg. try farmer takes cabbage e e w e % från w e w w try farmer takes wolf w w w e % från föreg. try farmer takes wolf e e w e % från föreg. try farmer takes goat e w e e % från w w w e try farmer takes goat w w w e % från föreg. try farmer takes cabbage w w e w % från e w e e BACKTRACK from: e w e e % dead end BACKTRACK from: w w w e % dead end

107 Körning © Patrick Blackburn, Johan Bos & Kristina Striegnitz try farmer takes cabbage w e w w % från e e w e try farmer takes self w e w e % från e e w e try farmer takes goat e e e e % från föreg. Solution Path Is: state(w,w,w,w) % start state(e,w,e,w) % farmaren tar geten... state(w,w,e,w) %... och ror ensam tillbaka state(e,e,e,w) % farmaren tar vargen... state(w,e,w,w) %... och ror tillbaka med geten state(e,e,w,e) % farmaren tar kålhuvudet... state(w,e,w,e) %... och ror ensam tillbaka state(e,e,e,e) % farmaren hämtar geten. true. % Alla har korsat floden.

108 Tillståndsgrafen... © Patrick Blackburn, Johan Bos & Kristina Striegnitz (w w w w) (e w e w) (w w e w) (e e e w) (w e w w) (e e w e) (w w w e) (e w e e) (w w e w) (w e w w) (w e w e) (e e e e)

109 © Patrick Blackburn, Johan Bos & Kristina Striegnitz Nästa FL: aritmetik i Prolog


Ladda ner ppt "© Patrick Blackburn, Johan Bos & Kristina Striegnitz FL 4: Listor (kap. 4 & 6) Teori –Introducera listor, en viktig rekursiv datastruktur som ofta används."

Liknande presentationer


Google-annonser