Föreläsning 3: rekursion Teori Introducera rekursiva definitioner i Prolog Fyra exempel Visa att det kan finnas diskrepanser mellan Prolog-programmets deklarativa och procedurala betydelse!
Rekursiva definitioner Prolog-predikat kan definieras rekursivt Ett predikat är rekursivt definierat om en eller flera regler i dess definition refererar till detta predikat.
Exempel 1: Eating isdigesting(x,y):- justate(x,y). isdigesting(x,y):- justate(x,z), isdigesting(z,y). justate(mosquito,blood(john)). justate(frog,mosquito). justate(stork,frog).?-
En bild av läget... justate X isdigesting Y
En bild av läget... X X justate isdigesting justate Z Y myggan som drack Johns blod isdigesting isdigesting Y
Exempel 1: Eating isdigesting(x,y):- justate(x,y). isdigesting(x,y):- justate(x,z), isdigesting(z,y). justate(mosquito,blood(john)). justate(frog,mosquito). justate(stork,frog).?- isdigesting(stork,mosquito).
En annan rekursiv definition p:- p.?-
En annan rekursiv definition p:- p.?- p.
En annan rekursiv definition p:- p.?- p. ERROR: out of memory
Exempel 2: descendant child(bridget,caroline). child(caroline,donna). descend(x,y):- child(x,y). descend(x,y):- child(x,z), child(z,y). Tolkning av child(x, Y): X has_child Y
Exempel 2: Descendant child(bridget,caroline). child(caroline,donna). descend(x,y):- child(x,y). descend(x,y):- child(x,z), child(z,y). Tolkning av descend(x, Y): Y descends from X
Exempel 2: Descendant child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,y). descend(x,y):- child(x,z), child(z,y). anna bridget caroline donna emily
Exempel 2: Descendant child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,y). descend(x,y):- child(x,z), child(z,y).?- descend(anna,donna). no?- anna bridget caroline donna emily
Exempel 2: Descendant child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,y). descend(x,y):- child(x,z), child(z,y). descend(x,y):- child(x,z), child(z,u), child(u,y).?- anna (X) bridget (Z) caroline (U) donna (Y) emily
Exempel 2: Descendant child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,y). descend(x,y):- child(x,z), descend(z,y).?- anna bridget caroline donna emily
Exempel 2: Descendant child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,y). descend(x,y):- child(x,z), descend(z,y).?- descend(anna,donna). anna bridget caroline donna emily
Sökträd Rita sökträdet för?- descend(anna,donna). anna child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,y). descend(x,y):- child(x,z), descend(z,y). bridget caroline donna emily
Sökträd descend(anna, donna)? r1 r2 child(anna, donna)? child(anna,_g395), descend(_g395, donna)? F child(anna, bridget) descend(bridget, donna)? r1 child(bridget, donna)? F r2 child(bridget,_g395), descend(_g395, donna)?
Sökträd child(bridget,_g395), descend(_g395, donna)? r1 r2 child(bridget, caroline) child(caroline, donna)? true r1 descend(caroline, donna)? r2 child(caroline,_g395), descend(_g395, donna)? Glöm inte att prolog söker alla sätten att bevisa målet!
Sökträd child(caroline,_g395), descend(_g395, donna)? r1 child(caroline, donna) r2 descend(donna, donna)? r1 r2 child(donna, donna)? child(donna,_g395), descend(_g395, donna)? F r1 r2 child(donna, emily) descend(emily, donna)? r1 r2 child(emily, donna)? child(emily,_g395), descend(_g395, donna)? F F
Trace descend(anna, donna). trace]?- descend(anna, donna). Call: (6) descend(anna, donna)? creep Call: (7) child(anna, donna)? creep Fail: (7) child(anna, donna)? creep Redo: (6) descend(anna, donna)? creep Call: (7) child(anna, _G415)? creep Exit: (7) child(anna, bridget)? creep Call: (7) descend(bridget, donna)? creep Call: (8) child(bridget, donna)? creep Fail: (8) child(bridget, donna)? creep Redo: (7) descend(bridget, donna)? creep Call: (8) child(bridget, _G415)? creep Exit: (8) child(bridget, caroline)? creep Call: (8) descend(caroline, donna)? creep Call: (9) child(caroline, donna)? creep Exit: (9) child(caroline, donna)? creep Exit: (8) descend(caroline, donna)? creep Exit: (7) descend(bridget, donna)? creep Exit: (6) descend(anna, donna)? creep true ;
Trace descend(anna, donna). Redo: (8) descend(caroline, donna)? creep Call: (9) child(caroline, _G415)? creep Exit: (9) child(caroline, donna)? creep Call: (9) descend(donna, donna)? creep Call: (10) child(donna, donna)? creep Fail: (10) child(donna, donna)? creep Redo: (9) descend(donna, donna)? creep Call: (10) child(donna, _G415)? creep Exit: (10) child(donna, emily)? creep Call: (10) descend(emily, donna)? creep Call: (11) child(emily, donna)? creep Fail: (11) child(emily, donna)? creep Redo: (10) descend(emily, donna)? creep Call: (11) child(emily, _G415)? creep Fail: (11) child(emily, _G415)? creep Fail: (10) descend(emily, donna)? creep Fail: (9) descend(donna, donna)? creep Fail: (8) descend(caroline, donna)? creep Fail: (7) descend(bridget, donna)? creep Fail: (6) descend(anna, donna)? creep false. Kunde inte bevisas på ett annat sätt.
Exempel 3: Successor Anta att vi använder följande sätt att skriva nummer: 1. 0 är ett nummer. 2. Om X är ett nummer, så är även succ(x).
Exempel 3: Successor numeral(0). numeral(succ(x)):- numeral(x).
Exempel 3: Successor numeral(0). numeral(succ(x)):- numeral(x).?- numeral(succ(succ(succ(0)))). yes?-
Exempel 3: Successor numeral(0). numeral(succ(x)):- numeral(x).?- numeral(x).
Exempel 3: Successor numeral(0). numeral(succ(x)):- numeral(x).?- numeral(x). X=0; X=succ(0); X=succ(succ(0)); X=succ(succ(succ(0))); X=succ(succ(succ(succ(0))))
Exempel 4: Addition?- add(succ(succ(0)),succ(succ(succ(0))), Result). Result=succ(succ(succ(succ(succ(0))))) yes
Exempel 4: Addition add(0,x,x). %%% base clause?- add(succ(succ(0)),succ(succ(succ(0))), Result). Result=succ(succ(succ(succ(succ(0))))) yes
Exempel 4: Addition add(0,x,x). %%% base clause add(succ(x),y,succ(z)):- add(x,y,z). %%% recursive clause?- add(succ(succ(0)),succ(succ(succ(0))), Result). Result=succ(succ(succ(succ(succ(0))))) yes succ(x) + Y blir succ(z) om X + Y är Z.
Sökträd Rita sökträdet för add(succ(succ(0)), succ(succ(succ(0))), R).
Sökträd add(0,x,x). add(succ(x),y,succ(z)):- add(x,y,z). add(succ(succ(0)), succ(succ(succ(0))), R). R = succ(r1) add((succ(0), succ(succ(succ(0))), R1). R1 = succ(r2) add(0, succ(succ(succ(0))), R2). basfall: R2 = succ(succ(succ(0)))
Sökträd add(0,x,x). add(succ(x),y,succ(z)):- add(x,y,z). add(succ(succ(0)), succ(succ(succ(0))), R). R = succ(r1) R = succ(succ(succ(succ(succ(0))))) add((succ(0), succ(succ(succ(0))), R1). R1 = succ(r2) R1 = succ(succ(succ(succ(0)))) add(0, succ(succ(succ(0))), R2). basfall: R2 = succ(succ(succ(0)))
Trace... [trace]?- add(succ(succ(0)), succ(succ(succ(0))), Z). Call: (6) add(succ(succ(0)), succ(succ(succ(0))), _G348)? creep Call: (7) add(succ(0), succ(succ(succ(0))), _G424)? creep Call: (8) add(0, succ(succ(succ(0))), _G426)? creep Exit: (8) add(0, succ(succ(succ(0))), succ(succ(succ(0))))? creep Exit: (7) add(succ(0), succ(succ(succ(0))), succ(succ(succ(succ(0)))))? creep Exit: (6) add(succ(succ(0)), succ(succ(succ(0))), succ(succ(succ(succ (succ(0))))))? creep Z = succ(succ(succ(succ(succ(0))))).
Prolog och logik Prolog var det första rimliga försöket att skapa ett språk för logikprogrammering Programmeraren ger en deklarativ specifikation av problemet, mha logikens språk Programmeraren borde inte behöva berätta för datorn vad den ska göra För att få information ger programmeraren helt enkelt en förfrågning
Prolog och logic Prolog innebär flera viktiga steg i denna riktning, men trots allt är Prolog inte ett fullständigt logikprogrammeringsspråk! Prolog har ett specifikt sätt att besvara förfrågningar: Sök kunskapsbasen uppifrån ner Processera satserna från vänster till höger Backtracka för att ersätta dåliga val eller för att söka efter flera svar/bevis.
descend1.pl child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,y). descend(x,y):- child(x,z), descend(z,y).?- descend(a,b). A=anna B=bridget
descend2.pl child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,z), descend(z,y). descend(x,y):- child(x,y).?- descend(a,b). A=anna B=emily
descend2.pl child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,z), descend(z,y). descend(x,y):- child(x,y).?- descend(a,b). A=anna B=emily Ordningen där svaren ges ändras.
descend2.pl child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,z), descend(z,y). descend(x,y):- child(x,y).?- descend(a,b). A=anna B=emily Att ändra ordningen i vilken reglerna ges brukar inte annars ändra på programmets beteende.
descend3.pl child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- descend(z,y), child(x,z). descend(x,y):- child(x,y).?- descend(a,b). ERROR: OUT OF LOCAL STACK Vi har ändrat på ordningen av delmålen INNE i en regel
descend3.pl child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- descend(z,y), child(x,z). descend(x,y):- child(x,y).?- descend(a,b). ERROR: OUT OF LOCAL STACK Det första delmålet är rekursivt => evig rekursion!!
descend(x,y):- descend(z,y), child(x,z) descend3.pl descend(anna, donna) descend(w1, donna) descend(w2, donna) descend(w3, donna) descend(w4, donna)... child(anna, W1) En vänsterrekursiv regel
descend4.pl child(anna,bridget). child(bridget,caroline). child(caroline,donna). child(donna,emily). descend(x,y):- child(x,y). descend(x,y):- descend(z,y), child(x,z).?- descend(a,b). Vissa svar hittas, andra leder till evig rekursion
Övning Utgå från följande kunskapsbas: father_of(carl, erik). father_of(carl, lena). father_of(erik, stig). father_of(erik, lars). father_of(stig, janne). father_of(stig, brita). father_of(lars, lisa). father_of(lars, petter). mother_of(alli, carl). mother_of(lena, anna). mother_of(lena, kajsa). mother_of(lena, ellen). mother_of(lena, olle). mother_of(ulla, janne). mother_of(ulla, brita). mother_of(eva, lisa). mother_of(eva, petter).
Övning Skriv reglerna (predikaten) för: paternal_grandfather_of(x,y) maternal_grandfather_of(x,y) paternal_grandmother_of(x,y) maternal_grandmother_of(x,y) full_siblings(x, Y) half_siblings(x,y)
Sammandrag Idag har vi sett på rekursiva predikat Vi har också diskuterat skillnaden mellan ett Prolog-programs deklarativa och procedurala betydelse. Vi har identifierat några av Prologs svagheter som ett logikprogrammeringsspråk.
Nästa FL... Introducerar listorna i Prolog Viktig rekursiv datastruktur i Prologprogrammering Definierar predikatet member/2, ett grundläggande Prolog-verktyg för listhantering Diskuterar hur man rekursivt bearbetar listorna Extra: prolog i problemlösning Läckert!