Föreläsning 11 i programmeringsparadigm. Boxmodellen i Sicstus-manualen.

Relevanta dokument
Föreläsning 10 i programmeringsparadigm. Boxmodellen för append.

Föreläsning 9 i programmeringsparadigm. Unifiering (Brna Chapter 4.1).

Del : Funktionell programmering. I alla deluppgifterna, använd Haskell och skriv typen för de identifierare du definierar.

Del : Paradigmer allmänt.

Centrala begrepp i prolog och logikprogrammering. Annamaris lista

Support Manual HoistLocatel Electronic Locks

Nada KTH 2004 jan 12 Tentamen Programmeringsparadigm 2D1350 Skrivtid 5 h 8-13

Föreläsning 9 i programmeringsparadigm. Paradigmöversikt, paradigmhistoria, paradigmgeografi. Se även föreläsning 1.

Föreläsning 8. newtype Chess = Chess [(Square, Chessman)] -- data ist f newtype OK -- data istället för newtype krävs om >1 konstruerare.

Quicksort. Koffman & Wolfgang kapitel 8, avsnitt 9

Del : Paradigmer allmänt.

Webbregistrering pa kurs och termin

TDDC74 Lab 02 Listor, sammansatta strukturer

Preschool Kindergarten

12.6 Heat equation, Wave equation

Dagens föreläsning Programmering i Lisp Fö 7. Sammanfattning funktionell programmering Exempel på funktionella programspråk

Grafer, traversering. Koffman & Wolfgang kapitel 10, avsnitt 4

Vässa kraven och förbättra samarbetet med hjälp av Behaviour Driven Development Anna Fallqvist Eriksson

Nada Tentamensdag 2004 okt 18 Tentamen Programmeringsparadigm Skrivtid 5 h

DD1361 Programmeringsparadigm HT15

1. Compute the following matrix: (2 p) 2. Compute the determinant of the following matrix: (2 p)

Föreläsning 12 i programmeringsparadigm. Negering.

DD1361 Programmeringsparadigm HT17

Webbreg öppen: 26/ /

Nada KTH 2003 okt 23 Tentamen Programmeringsparadigm 2D1350 Skrivtid 5 h 8-13

Second handbook of research on mathematics teaching and learning (NCTM)

Stad + Data = Makt. Kart/GIS-dag SamGIS Skåne 6 december 2017

COMPUTABILITY BERÄKNINGSBARHET. Källa: Goldschlager, Lister: Computer Science A Modern Introduction 2. upplaga 1988, Prentice Hall

Deklarativt programmeringsparadigm

Kursanalys för Programmeringsparadigm 2D1361, läsperiod 1 och 2 läsåret 2005/2006

Föreläsning 9 Innehåll. Söndra och härska. Fibonaccitalen. Söndra och härska. Divide and conquer teknik för att konstruera rekursiva algoritmer.

DD1361 Programmeringsparadigm HT16

Scratch Junior. makeandshape.com. by MIT. Gränssnitt Scratch Junior

Authentication Context QC Statement. Stefan Santesson, 3xA Security AB

Föreläsning 13 i programmeringsparadigm.

Föreläsning 9 Innehåll. Söndra och härska. Fibonaccitalen. Söndra och härska. Divide and conquer teknik för att konstruera rekursiva algoritmer.

Isometries of the plane

Chapter 2: Random Variables

DVG C01 TENTAMEN I PROGRAMSPRÅK PROGRAMMING LANGUAGES EXAMINATION :15-13: 15

Problem som kan uppkomma vid registrering av ansökan

Beslut om bolaget skall gå i likvidation eller driva verksamheten vidare.

DD1361 Programmeringsparadigm. Carina Edlund

Lösenordsportalen Hosted by UNIT4 For instructions in English, see further down in this document

TDDC74 Programmering: Abstraktion och modellering Dugga 2, , kl 17-19

Par m 328 feet. Lång höger sväng. Korgen står placerad i en skogsglänta OB-linje på vänster sida.

Graphs (chapter 14) 1

F6: Högre ordningens funktioner. Mönster för rekursion (1) Mönster för rekursion (1b) Mönster för rekursion (2) Högre Ordningens Funktioner

Michael Q. Jones & Matt B. Pedersen University of Nevada Las Vegas

8 < x 1 + x 2 x 3 = 1, x 1 +2x 2 + x 4 = 0, x 1 +2x 3 + x 4 = 2. x 1 2x 12 1A är inverterbar, och bestäm i så fall dess invers.

Föreläsning 5 i programmeringsparadigm.

Lådmodellen....eller procedure box control flow model. Dynamisk bild av ett prologprogram Förklarar i detalj procedurell läsning av ett program.

Module 6: Integrals and applications

TDDC74 Programmering: Abstraktion och modellering Dugga 2, , kl 14-16

Pedagogisk planering. Ron Chlebek. Centralt Innehåll. Svenska/Engelska. Lego Mindstorms. Syfte: Matematik

Windlass Control Panel v1.0.1

Funktionell programmering DD1361

Health café. Self help groups. Learning café. Focus on support to people with chronic diseases and their families

Del : Funktionell programmering. I alla deluppgifterna, använd Haskell och skriv typen för de identifierare du definierar.

Att stödja starka elever genom kreativ matte.

Make a speech. How to make the perfect speech. söndag 6 oktober 13

DD1361 Programmeringsparadigm HT15

BOX SOLFALL. Anna Lamberg. 8 januari 7 februari

FORTA M315. Installation. 218 mm.

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson 2

Dagens föreläsning Programmering i Lisp Fö 5

Föreläsning 6 i programmeringsparadigm. Tips kring programmering i Haskell och kring labbarna.

DD1361 Programmeringsparadigm HT15

Ett hållbart boende A sustainable living. Mikael Hassel. Handledare/ Supervisor. Examiner. Katarina Lundeberg/Fredric Benesch

ASSEMBLY INSTRUCTIONS SCALE SQUARE - STANDARD

Länkning av Prolog under C

Information technology Open Document Format for Office Applications (OpenDocument) v1.0 (ISO/IEC 26300:2006, IDT) SWEDISH STANDARDS INSTITUTE

Föreläsning 4 (och 5?) i programmeringsparadigm.

Questionnaire for visa applicants Appendix A

x 2 2(x + 2), f(x) = by utilizing the guidance given by asymptotes and stationary points. γ : 8xy x 2 y 3 = 12 x + 3

1. Varje bevissteg ska motiveras formellt (informella bevis ger 0 poang)

Alias 1.0 Rollbaserad inloggning

Writing with context. Att skriva med sammanhang

Signatursida följer/signature page follows

samhälle Susanna Öhman

EU:s ministerkonferens för e-förvaltning under det svenska ordförandeskapet

Föreläsning 8. Paradigmöversikt, paradigmhistoria, paradigmgeografi. Se även föreläsning 1.

Föreläsning 4 IS1300 Inbyggda system

Pre-Test 1: M0030M - Linear Algebra.

Solutions to exam in SF1811 Optimization, June 3, 2014

Sätt att skriva ut binärträd

Isolda Purchase - EDI

KTH MMK JH TENTAMEN I HYDRAULIK OCH PNEUMATIK allmän kurs kl

TDDC74 Programmering: Abstraktion och modellering Datortenta , kl 14-18

Programmering I Tobias Wrigstad fredag, 2009 augusti 28

denna del en poäng. 1. (Dugga 1.1) och v = (a) Beräkna u (2u 2u v) om u = . (1p) och som är parallell

Mekanik FK2002m. Kraft och rörelse I

Hur fattar samhället beslut när forskarna är oeniga?

Användning av Erasmus+ deltagarrapporter för uppföljning

Calculate check digits according to the modulus-11 method


Rekursiva algoritmer sortering sökning mönstermatchning


Beijer Electronics AB 2000, MA00336A,

BOENDEFORMENS BETYDELSE FÖR ASYLSÖKANDES INTEGRATION Lina Sandström

Transkript:

Föreläsning 11 i programmeringsparadigm. Boxmodellen i Sicstus-manualen. The Procedure Box Control Flow Model During debugging, the debugger prints out a sequence of goals in various states of instantiation in order to show the state the program has reached in its execution. However, in order to understand what is occurring it is necessary to understand when and why the debugger prints out goals. As in other programming languages, key points of interest are predicate entry and return, but in Prolog there is the additional complexity of backtracking. One of the major confusions that vice Prolog programmers have to face is the question of what actually happens when a goal fails and the system suddenly starts backtracking. The Procedure Box model of Prolog execution views program control flow in terms of movement about the program text. This model provides a basis for the debugging mechanism in development systems, and enables the user to view the behavior of the program in a consistent way. Let us look at an example Prolog predicate : *--------------------------------------------* Call Exit ---------> + descendant(x,y) :- offspring(x,y). + ---------> descendant(x,z) :- <--------- + offspring(x,y), descendant(y,z). + <--------- Fail Redo *-------------------+-----------------------* The first clause states that Y is a descendant of X if Y is an offspring of X, and the second clause states that Z is a descendant of X if Y is an offspring of X and if Z is a descendant of Y. In the diagram a box has been drawn around the whole predicate and labeled arrows indicate the control flow in and out of this box. There are five (en fattas i min bearbetning av manualen) such arrows, which we shall look at in turn. Call Exit This arrow represents initial invocation of the predicate. When a goal of the form descendant(x,y) is required to be satisfied, control passes through the Call port of the descendant box with the intention of matching a component clause and then satisfying the subgoals in the body of that clause. Note that this is independent of whether such a match is possible; i.e. first the box is called, and then the attempt to match takes place. Textually we can imagine moving to the code for descendant when meeting a call to descendant in some other part of the code. This arrow represents a successful return from the predicate. This occurs when the initial goal has been unified with one of the component clauses and the subgoals have been satisfied. Control w passes out of the Exit port of the descendant box. Textually we stop following the code for descendant and go back to the place we came from.

Redo Fail This arrow indicates that a subsequent goal has failed and that the system is backtracking in an attempt to find alternatives to previous solutions. Control passes through the Redo port of the de scendant box. An attempt will w be made to resatisfy one of the component subgoals in the body of the clause that last succeeded; or, if that fails, to completely rematch the original goal with an alternative clause and then try to satisfy any subgoals in the body of this new clause. Textually we follow the code backwards up the way we came looking for new ways of succeed ing, possibly dropping down on to ather clause and following that if necessary. This arrow represents a failure of the initial goal, which might occur if clause is matched, or if subgoals are never satisfied, or if any solution produced is always rejected by later processing. Control w passes out of the Fail port of the descendant box and the system continues to back track. Textually we move back to the code that called this predicate and keep moving backwards up the code looking for choicepoints. Naiv lösning i Prolog för Sudoku-problem. Hur kontrollerar vi att en suduko-lösning är OK? Jo grupper om nio tal skall innehålla alla tal 1<= tal <= 9. En naiv lösnng: member(x, [X _]). member(x, [_ Ys]):- member(x,ys). ninecheck(xs) :- member(1,xs), member(2,xs),member(3,xs), member(4,xs), member(5,xs),member(6,xs), member(7,xs), member(8,xs),member(9,xs). I övergrupper on nio stycken niogrupper skall alla niogrupper uppfylla detta villkoret ninecheck: nxncheck([]). nxncheck([n Ns]):- ninecheck(n), nxncheck(ns). En sudoku är en 9 x 9-matris och kan skrivas som en lista med 9 rader, varje rad är i sin tur en lista med 9 element. Det finns tre övergrupper; matrisen radvis, kolonnvis och delkvadratvis. En delkvadrat är 3x3 matris och hela sudokun är en 3x3-matris med delkvadrater. En lösning är att skriva en predikat trans(s, St, Sg) där St är S transponerad och Sg är S förvandlad på så sätt att varje rad i Sg är talen i en delkvadrat. allcheck(s) kontrollerar då ett helt sudoku. allcheck(s) :- trans(s,st,sg), nxncheck(s), nxncheck(st), nxncheck(sg). trans([[x11,x12,x13,x14,x15,x16,x17,x18,x19], [X21,X22,X23,X24,X25,X26,X27,X28,X29], [X31,X32,X33,X34,X35,X36,X37,X38,X39], [X41,X42,X43,X44,X45,X46,X47,X48,X49], [X51,X52,X53,X54,X55,X56,X57,X58,X59], [X61,X62,X63,X64,X65,X66,X67,X68,X69], [X71,X72,X73,X74,X75,X76,X77,X78,X79], [X81,X82,X83,X84,X85,X86,X87,X88,X89], [X91,X92,X93,X94,X95,X96,X97,X98,X99]], [[X11,X21,X31,X41,X51,X61,X71,X81,X91], [X12,X22,X32,X42,X52,X62,X72,X82,X92], [X13,X23,X33,X43,X53,X63,X73,X83,X93], [X14,X24,X34,X44,X54,X64,X74,X84,X94], [X15,X25,X35,X45,X55,X65,X75,X85,X95],

[X16,X26,X36,X46,X56,X66,X76,X86,X96], [X17,X27,X37,X47,X57,X67,X77,X87,X97], [X18,X28,X38,X48,X58,X68,X78,X88,X98], [X19,X29,X39,X49,X59,X69,X79,X89,X99]], [[X11,X12,X13, X21,X22,X23, X31,X32,X33], [X14,X15,X16, X24,X25,X26, X34,X35,X36], [X17,X18,X19, X27,X28,X29, X37,X38,X39], [X41,X42,X43, X51,X52,X53, X61,X62,X63], [X44,X45,X46, X54,X55,X56, X64,X65,X66], [X47,X48,X49, X57,X58,X59, X67,X68,X69], [X71,X72,X73, X81,X82,X83, X91,X92,X93], [X74,X75,X76, X84,X85,X86, X94,X95,X96], [X77,X78,X79, X87,X88,X89, X97,X98,X99]]). Om vi definierar ett faktum : s115([[5,6,8,4,9,3,2,1,7], %så kan vi t ex testa?- s115(s),allcheck(s). [1,3,4,5,2,7,6,8,9], S =... [9,7,2,6,1,8,4,5,3], yes [2,5,9,7,4,6,1,3,8], [6,4,1,3,8,9,7,2,5], [7,8,3,2,5,1,9,4,6], [8,2,6,9,3,4,5,7,1], [3,9,5,1,7,2,8,6,4], [4,1,7,8,6,5,3,9,2]]). Men Prologpredikat kan ju köras "baklänges; i princip kan vi alltså använda vårt program för att lösa en sudoku där en del tal fattas : s17(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q, [[5,6,K,4,9,L,2,1,7], [1,3,4,5,J,7,D,8,9], [9,7,2,6,1,8,4,5,3], [2,Q,9,7,A,O,1,3,8], %så kan vi t ex testa [F,4,1,3,8,P,7,G,5], [N,8,B,2,5,C,9,4,6],?- s17(a,b,c,...s), allcheck(s). [8,2,6,H,3,4,5,7,1], A = 4, [3,9,5,1,M,2,8,6,4], B = 3,... [4,1,I,8,6,5,3,E,2]]). Körtiden är några sekunder för detta problem där 17 element saknas. Saknas fler element ökar körtiden snabbt.problemen i tidningarna saknar dock kring 50 st element. Ska vi skriva ett realistiskt program måste vi börja tänka. Det borde gå lite fortare att använda en ninecheck som arbetar med labbens select istället för member men skillnaden är inte stor, jag har provat. Att det börjar ta tid beror ju på att det snabbt blir väldigt mycket "back-tracking". I vår lösning kommer ju ibland körningar av member att ge substitutioner av de logiska variablerna i sodokun, dvs Prolog chansar på at det ska vara en 1 och går vidare, går inte det så kanske en 2 går bättre, osv. Lösningen ovan kan ses som ett exempel på tekniken "Generate -Test", Brna sid 70. Sådana problem kan ofta effektiviseras gem att "skjuta testet in i generatorn". I lättare sudokun går det att finna element som man direkt kan bestämma, vilket gör att kanske ytterligare element kan bestämmas osv. Eventuellt behövs ingen backtracking alls. Sökning på Google med sudoku och prolog ger förstås massor av träffar: Här är t ex en ("full-working"): http://www.allpowerfuldave.com/games/sudoku/sudoku.pl Mitt program på /info/progp05/sudoku.pl.

Diskutabel bild om paradigmer och programmering av problem av "programmeringstävlings-typ". svårighet jobbigt Bilden mest för kombinatoriska problem? Tvungen att komma på effektiv algoritm, ändå hur? imperativ programmering, OO massa fåninga hur-detaljer????? Paradigm-obedroende? bekvämt funktionell programmering logikprogrammering logikläsning duger djupet-först, backtrackning gratis djupet-först, duger ej Algoritmen det svåra, ej att fomulera den? Kunna ADK? snitt, trixs, icke-logisk Prolog nästa föreläsning procedurell läsning krävs terminering problem sökträdsstorlek problem lösning i rätt ordning viktig osv problemstorlek n

Boxmodellen för append. % append(xs, Ys, XsYs) XsYs är resultatet när man konkatenerar listorna Xs och Ys % Haskell: append([], Ys, Ys). % (++) [] ys = ys append([x Xs],Ys,[X Zs]):-append(Xs,Ys,Zs). % (++) (x:xs) ys = x:(xs ++ ys) % Haskell med namn på rekursionantagandet % (++) (x:xs) ys = x:zs where zs=(xs++ys) Jag försöker förklara bilden nedan för en körning av append([1,2], [3, 4], Rs) närmare på föreläsningen. Principen är att vid anrop (Call) unifieras anropets argument med parametrarna i huvudet på den klausul som används, dvs en massa substitutioner sker. Substitutionerna är skrivna med kursiv stil i bilden nedan. Sker därefter ytterligaren ett anrop så sker ytterligare substitutioner osv. Vid en lyckad körning, dvs när vi lämmnar Exit-porten i den yttersta lådan som representerar frågan, så har det bildas en "kanal" kopplad till allt mer detaljerade värden på olika logiska variabler, och de logiska variablerna i frågan kan ges som ett detaljerat förslag. I bilden nedan har till slut Rs alias _276 blivit [1, 2, 3, 4]när vi kommer ut till höger. append([1, 2], [3, 4], Rs). append([], Ys, Ys). append/1 nivå 1 append([], Ys, Ys). append/2 nivå 2 append([x Xs],Ys,[X Zs]) X=1 Xs = [2] Ys = [3, 4] [X Zs] = Rs = _276 _276 = [1 _775] append([x Xs],Ys,[X Zs]) X=2 _775 = [2 _1169] Xs = [] Ys = [3, 4] append/3 nivå 3 append([], Ys, Ys). Ys = [3, 4] _1169 =[3,4] append([x Xs.. append([], Ys, Ys). append([x Xs], Ys, [X Zs]) :- append(xs, Ys, Zs).?- append([1, 2], [3, 4], Rs). 1 1 Call: append([1,2],[3,4],_276)? 2 2 Call: append([2],[3,4],_775)? 3 3 Call: append([],[3,4],_1169)? 3 3 Exit: append([],[3,4],[3,4])? 2 2 Exit: append([2],[3,4],[2,3,4])? 1 1 Exit: append([1,2],[3,4],[1,2,3,4])? Rs = [1,2,3,4]? yes Vid en mer invecklad körning, av annan program databas, där "backtracking" förkommit (Fail och Redo-portar har passerats "åt vänster"), så används inte de substitutioner som görs i de misslyckade sökförsöken, dvs i de grenar av sökträdet som inte "nått fram" till Exit- porten i frågans predikat. Sökträdet

Prologpredikat kan användas på många sätt. Se Brna avsnitt 6.1, The Reversibility of Prolog Programs. Ett lysande exempel på detta är append(?,?,?), som kan användas på massor av sätt.? betyder att argumentet kan vara både "inargument" och "utargument". Körningar på en mängd olika sätt: %append(+, +, 1) dvs append?- append([1, 2, 14], [22, 33], Res).% Vanlig använding, "som vi tänkte " Res = [1,2,14,22,33]? ; % append(+, +, -) + "in" - "out" % Funktion : Se föregående sida?- append([1], R, [1, 2, 3]). %append(+, -, +) suffix R = [2, 3]? ; % med trace: 1 1 Call: append([1],_228,[1,2,3])? 2 2 Call: append([],_228,[2,3])? 2 2 Exit: append([],[2,3],[2,3])? 1 1 Exit: append([1],[2,3],[1,2,3])? R = [2,3]? ;?- append(res, [22,33], [1,2,14,22,33] ). %append(+, -, +) prefix Res = [1,2,14]? ;?- append(r1, R2, [1,2,14]). %append(-, -, +) split R1 = [], R2 = [1,2,14]? ; R1 = [1], R2 = [2,14]? ; R1 = [1,2], R2 = [14]? ; R1 = [1,2,14], R2 = []? ; % med trace:?- append(r1, R2, [1,2,14]). 1 1 Call: append(_208,_230,[1,2,14])? 1 1 Exit: append([],[1,2,14],[1,2,14])? R1 = [], R2 = [1,2,14]? ; 1 1 Redo: append([],[1,2,14],[1,2,14])? 2 2 Call: append(_775,_230,[2,14])? 2 2 Exit: append([],[2,14],[2,14])? 1 1 Exit: append([1],[2,14],[1,2,14])? R1 = [1], R2 = [2,14]? ; 1 1 Redo: append([1],[2,14],[1,2,14])? 2 2 Redo: append([],[2,14],[2,14])? 3 3 Call: append(_1168,_230,[14])? 3 3 Exit: append([],[14],[14])? 2 2 Exit: append([2],[14],[2,14])? 1 1 Exit: append([1,2],[14],[1,2,14])? R1 = [1,2], R2 = [14]? ; 1 1 Redo: append([1,2],[14],[1,2,14])? 2 2 Redo: append([2],[14],[2,14])? 3 3 Redo: append([],[14],[14])? 4 4 Call: append(_1560,_230,[])? 4 4 Exit: append([],[],[])? 3 3 Exit: append([14],[],[14])? 2 2 Exit: append([2,14],[],[2,14])? 1 1 Exit: append([1,2,14],[],[1,2,14])?

R1 = [1,2,14], R2 = []? ; 1 1 Redo: append([1,2,14],[],[1,2,14])? 2 2 Redo: append([2,14],[],[2,14])? 3 3 Redo: append([14],[],[14])? 4 4 Redo: append([],[],[])? 4 4 Fail: append(_1560,_230,[])? 3 3 Fail: append(_1168,_230,[14])? 2 2 Fail: append(_775,_230,[2,14])? 1 1 Fail: append(_208,_230,[1,2,14])? I Haskell kan vi inte använda (++) för att splittra listor, vi måste skriva en invers funktion: splits :: [a] -> [ ([a],[a]) ] splits [] = [ ([],[]) ] splits (x:xs) = ([], x:xs) : map f (splits xs) where f (a, b) = (x:a, b) I Prolog kan vi nu använda append/3 för att enkelt definiera t ex : prefix(xs, Ys) :- append(xs, _, Ys). suffix(xs, Ys) :- append( _, Xs, Ys). member(x, Ys) :- append(_, [X Xs], Ys). member/2 kan alternativt definieras som i Brna 6.3.1 sid 57, vi har ju dessutom gjort det för sudokuproblemt : member(x,[x Xs]). member(x,[y Ys]) :- member(x,ys). % Y kan ersättas med _. Körningar av member/2:?- member(5, [3, 5, 6, 7]). yes?- member(x, [3, 5, 6]). X = 3? ; X = 5? ; X = 6? ;?- member(3, Rs). Rs = [3 _A]? ; Rs = [_A,3 _B]? ; Rs = [_A,_B,3 _C]? yes?- member(r, Rs). Rs = [R _A]? ; Rs = [_A,R _B]? yes Ytterligare ett exempel: adjacent(x, Y, Zs) :- append(_, [X,Y Ys], Zs). last(x, Xs) :- append(_, [X], Xs). Körningar:?- adjacent(14, 28, [23, 14, 28, 45]). yes?- adjacent(14, R, [23, 14, 28, 45]). R = 28? ;

Program med "ackumulering i parameter". 1. Rekursiv definiton av reverse/2: % reverse(list, Tsil) :- Tsil är listan List med elmenten i omvänd ordning reverse1([], []). reverse1([x Xs], Zs):- reverse1(xs, Ys), append(ys, [X], Zs). Körning:?- reverse1([1, 2], Res). Res = [2,1]? ;?- reverse1(res, [1, 2]). Res = [2,1]? ; % Inget händer gör C-c Prolog interruption (h for help)? a {Execution aborted}?- trace.?- reverse1([1, 2], Res). 1 1 Call: reverse1([1,2],_224)? 2 2 Call: reverse1([2],_702)? 3 3 Call: reverse1([],_1100)? 3 3 Exit: reverse1([],[])? 4 3 Call: append([],[2],_702)? 4 3 Exit: append([],[2],[2])? 2 2 Exit: reverse1([2],[2])? 5 2 Call: append([2],[1],_224)? 6 3 Call: append([],[1],_3351)? 6 3 Exit: append([],[1],[1])? 5 2 Exit: append([2],[1],[2,1])? 1 1 Exit: reverse1([1,2],[2,1])? Res = [2,1]? ; Brna kallar detta sätt att resonera för "Building Structure in the Clause Head", se sid 60 långt ner på sidan. (Ovanför står avsiktligt ett helt felaktigt sätt att resonera). I sitt exempel använder Brna is. Till höger om is kan man skriva uttryck som räknas ut och unifieras med det som står till vänster om is, dvs man har tillgång till en funktionellt delspråk i Prolog. Se Brna avsnitt 6.1.1Vi kommer inte att använda detta mycket, kanske inte alls. 2. Definition av reverse/2 med hjälp av "ackumulering i parameter" i hjälpfunktion reverse/2 : reverse(xs, Ys) :- reverse(xs, [], Ys). reverse([x Xs], Acc, Ys) :- reverse(xs, [X Acc], Ys). reverse([], Ys, Ys). Körning:?- reverse([1, 2], Res). Res = [2,1]? ;?- reverse(res, [1, 2]). Prolog interruption (h for help)? a {Execution aborted}?- reverse([1,2], Res). 1 1 Call: reverse([1,2],_224)? 2 2 Call: reverse([1,2],[],_224)?

3 3 Call: reverse([2],[1],_224)? 4 4 Call: reverse([],[2,1],_224)? 4 4 Exit: reverse([],[2,1],[2,1])? 3 3 Exit: reverse([2],[1],[2,1])? 2 2 Exit: reverse([1,2],[],[2,1])? 1 1 Exit: reverse([1,2],[2,1])? Res = [2,1]? ; Märk att vi kan ha samma namn på två olika pedikat, ariteten (ställigheten, i vårt fall /2 respektive /3) räcker för att Prolog ska kunna skilja på predikaten. I Haskell måste varje namn ha en unik definition i sitt "scope". Brna kallar detta sätt att resonera för "Building Structure in the Clause Body", se sid 61. Avsnitt 6.1, 6.2 och 6.3 innehåller en hel del om programmeringsteknik i Prolog och om hur man programmerar listor.. Exempel på sorteringar. Insättningsortering i Prolog och Haskell (Haskellprogrammet modifierat från sid 44 i Fokker) sortlk([x Xs],Ys) :- sortlk(xs,zs), insert(x,zs,ys). sortlk([],[]). insert(x,[],x). insert(x,[y Ys],[Y Zs]) :- X > Y, insert(x,ys,zs). insert(x,[y Ys],[X,Y Ys]) :- X =< Y. sort :: Ord a => [a] -> [a] sort (x:xs) = insert x (sort xs) sort [] = [] insert:: Ord a => a-> [a] -> [a] insert x [] = [x] insert x (y:ys) x > y = y: insert x ys otherwise = x:y:ys I Prolog är > en operator. Operatorer är också predikat men med vissa speciella egenskaper, bl a används många med infix-placering. För att förstå sorteringsprogrammet ovan räcker det att förstå att t ex 3 < 5 lyckas, 5>=17 misslyckas. Operatorn = betyder att en unifiering sker. Även quicksort blir ganska lika: /*sort(xs,ys) :- The list Ys is an ordered permutation of the Xs. /* quicksort([x Xs],Ys) :- partition(xs,x,littles,bigs), quicksort(littles,ls), quicksort(bigs,bs), append(ls,[x Bs],Ys). quicksort([],[]). partition([x Xs],Y,[X Ls],Bs) :- X =< Y, partition(xs,y,ls,bs). partition([x Xs],Y,Ls,[X Bs]) :- X > Y, partition(xs,y,ls,bs). partition([],y,[],[]). -- Haskell : quicksort :: Ord a => [a] - [a] quicksort (x:xs) = ls ++ [x] ++ bs where (littles,bigs) = partion(xs, x) ls = quicksort littles, bs = quicksort bigs quicksort [] =[] partition Ord a => [a] -> a ->([a],[a]) partition (x:xs) y x <= y = (x :ls, bs) otherwise = (ls, x:bs) where (ls, bs) = partition xs y partition [] = ([],[]).

Predikatet permutation från labben kan användas i en (ineffektiv) sortering : sort(xs,ys) :- permutation(xs,ys), ordered(ys). ordered([]). ordered([x]). ordered([x,y Ys]) :- X =< Y, ordered([y Ys]). Generate och test. Inför labben "Tidernas knepigaste problem". Det står lite grann om detta i Brna avsnitt 7.3, sid 70 till 72 ungefär. Ett exempel som liknar labben "Tidernas knepigaste problem" finns i labhäftet. Programmering i ren Prolog. Ren Prolog (pure Prolog) definieras som att allt i programmet har en logisk läsning. Man rekommenderar att man börjar programmera på detta sätt och tänker på programmet med den logiska läsningen, och det har vi gjort än så länge. I den logiska läsningen spelar klausul-ordningen ingen roll, och delmålen i en regelkropp spelar ingen roll. I regel måste man även i rena Prologprogram läsa programmet med en procedurell syn, för att programmet skall fungera (t ex inte gå in i en evig loop), bli snabbt mm. Det gäller bl a att klausul-ordningen bestämmer i vilken ordning man får lösningarna Finns "oändliga lösningar" är detta viktigt, i annat fall om man vill se alla lösningar mindre viktigt. ordningen mellan delmålen i en regels vänsterled bestämmer hur sökningen går till. I apan-och-bananen-problemet på nästa sida får vi "oändliga lösningar först", dvs datorn svarar inte, om klausul-ordningen är olämplig.

Apan och bananen (inte BanArne). Efter Bratko 2.5. Apan vid dörren är hungrig, men kan inte nå bananen som hänger för högt upp i mitten på rummet. Vid fönstret står en låda. Om lådan skulle stå mitt under bananen skulle apan nå bananen om den steg upp på lådan. Kan apan stilla sin hunger? Hur? atdoor middle atwindow Lösning: (på /info/progp02/prolog/monkey.pl ) % state(horizontal position of monkey (atdoor/atwindow/middle), % vertical position of monkey( onbox/onfloor), % position of box (atdoor/atwindow/middle), % possesion of banana (has/hast)). % move(prestate, Action, PostState) Action changes state from PreState to % PostState. move(state(middle, onbox, middle, hast), grasp, state(middle, onbox, middle, has)). move(state(p, onfloor, P, H), climb, state(p, onbox, P, H)). move(state(p1, onfloor, P1, H), push(p1, P2), state(p2, onfloor, P2, H)). move(state(p1, onfloor, B, H), walk(p1, P2), state(p2, onfloor, B, H)). % canget(state, Actions) -- monkey can get the banana from state State by % performing the actions Actions. canget(state(_, _, _, has), []). canget(state1, [Action As]) :- move(state1, Action, State2), canget(state2, As). /* Körning :?- canget(state(atdoor, onfloor, atwindow, hast), Rs). Rs = [walk(atdoor,atwindow),push(atwindow,middle),climb,grasp]? ; Rs = [walk(atdoor,atwindow),push(atwindow,_a),push(_a,middle),climb,grasp]? ; Rs = [walk(atdoor,atwindow),push(atwindow,_a),push(_a,_b),push(_b,middle),climb,grasp]? yes */

Från Ny teknik om sudoku: Det nya sifferpusslet sudoku har blivit en dundersuccé i Sverige. De flesta stora dagstidningarna publicerar i dag pusslet, som går ut på att fylla ett rutnät med siffror efter lättbegripliga regler. Vissa sudoku är mycket enkla att lösa. Men matematikerna har fått sig en del huvudbry när de dykt ner i matematiken kring det nya sifferpusslet. En grundläggande matematisk fråga är hur många olika sudoku som är möjliga att skapa. Alltså på hur många sätt de 81 siffrorna på spelplanen kan kombineras med varandra enligt reglerna för spelet. Trots att pusslet varit känt sedan 1970-talet och varit en jättefluga i Japan under tiotals år fick frågan sitt svar först i maj 2005. - Att det tog så lång tid beror g på att matematiker tidigare inte varit seriöst intresserade av sudoku, säger Paul Vaderlind, som är matematiker vid Stockholms universitet. - För dem som är insatta i kombinatorik är det relativt enkelt att räkna ut hur många det finns. Olika svårighetsgrad Svårigheten att lösa pusslet hänger nära samman med hur många av de 81 rutorna som är ifyllda från början. Med 35 givna siffror är pusslet ofta ganska lätt, medan 25 kända siffror kan erbjuda många timmars funderande, sifferplitande och suddande. FAKTA SUDOKU Antalet kombinationer bevisat Den tyska matematikern Bertram Felgenhauer blev först med att publicera svaret på hur många olika sudoku som kan konstrueras. Han bevisade att det finns 6 670 903 752 021 072 936 960 olika sätt att kombinera de 81 siffrorna enligt reglerna för pusslet. Hur många siffror som minst måste vara givna för att pusslet bara ska ha en lösning, och alltså vara en äkta sudoku, finns inget bevis för. Det lägsta antalet som är känt idag är 17. Men för bara några månader sedan var det 19. En annan fråga som väntar på sitt svar är hur många av de nio små kvadraterna med 3 x 3 siffror som helt kan sakna givna siffror i en lösningsbar sudoku. Det bästa exemplet som Paul Vaderlind sett har tre helt tomma kvadrater och ytterligare två kvadrater med endast en given siffra i varje. Alltså fem kvadrater som tillsammans bara innehåller två givna siffror. Regler: Varje lodrät och vågrät rad liksom de nio mindre kvadraterna ska innehålla siffrorna ett till nio. Varje siffra får bara förekomma en gång i varje rad och kvadrat.