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

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

Del : Paradigmer allmänt.

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

Tentamensdag 2002-aug-20 Tentamen i Funktionell Programmering Skrivtid 5 h

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

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

Del : Paradigmer allmänt.

Centrala begrepp i prolog och logikprogrammering. Annamaris lista

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

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.

Kap9. Operatorn.. Hudak 9.4 sid 11. Fermats förmodan, eller Fermats stora sats säger att. xm + ym == zm har heltalslösningar om och endast om m == 2.

Föreläsning 4 i programmeringsparadigm.

Nada Tentamensdag 2004 okt 18 Tentamen Programmeringsparadigm Skrivtid 5 h

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

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

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

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

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

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

Föreläsning 12 i programmeringsparadigm. Negering.

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

DD1361 Programmeringsparadigm HT15

Föreläsning 13 i programmeringsparadigm.

Föreläsning 5 i programmeringsparadigm.

DD1361 Programmeringsparadigm HT17

DD1361 Programmeringsparadigm HT15

DD1361 Programmeringsparadigm HT15

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

I kapitel 15 gör Hudak för reaktiva animeringar detsamma som han i kapitel 13 gör för animeringar. Resultatet är en module Fal.

Nada, KTH Tentamensdag maj -24 Tentamen i Funktionell Programmering Skrivtid 5 h

Föreläsning 8. Hudak kapitel 13. 2D1370 Funktionell programmering v15 torsdag

DD1361 Programmeringsparadigm. Carina Edlund

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

Kungliga Tekniska Högskolan Ämneskod 2D1370 Tentamensdag 2001-maj-31 Tentamen i Funktionell Programmering Skrivtid 4 h

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

DD1361 Programmeringsparadigm HT16

Enjoy Vattenfallsmodellen i funktionella språk

Programkonstruktion och datastrukturer. Moment 9 Om högre ordningens funktioner. PKD 2010/11 moment 9 Sida 1 Uppdaterad

Enjoy Vattenfallsmodellen i funktionella språk

Lambdas. (och fler design patterns) Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2017

Föreläsning 3: rekursion

Länkning av Prolog under C

Föreläsning 7 i programmeringsparadigm. Ytterligare Högre ordningens funktioner: filter, foldr foldl. Hutton 7.2, 7.3 och 7.4.

Sortering. Brute-force. Sortering Ordna element enligt relation mellan nyckelvärden

Programkonstruktion och datastrukturer. Moment 9 Om högre ordningens funktioner. PKD 2011/12 moment 9 Sida 1 Uppdaterad

Tentamen. Datalogi I, grundkurs med Java 10p, 2D4112, Lördagen den 30 november 2002 kl , salar E33, E34

Sätt att skriva ut binärträd

Grundläggande logik och modellteori

Traditionell Programmering

Men först: Några funktioner ur preluden. Introduktion till programmering. Uppgiften. Variationer av uppgiften. Föreläsning 4

Funktionell programmering DD1361

TDDC74 Programmering: Abstraktion och modellering Tentamen, lördag 27 augusti 2016, kl 8 12

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

Tentamen TEN1 HI

Övningsuppgifter kapitel 8

Lab5 för prgmedcl04 Grafik

Rekursion och induktion för algoritmkonstruktion

Några inbyggda funktioner (med resultat!) Introduktion till programmering D0009E. Föreläsning 4: Villkor och rekursion. Modulus-operatorn.

Planering Programmering grundkurs HI1024 HT TIDAA

LÖSNINGSFÖRSLAG TENTAMEN PROGRAMMERING I ETT FUNKTIONELLT SPRÅK ML, 5P

Haskell forts. 5DV085 - Programspråk. Jan Erik Moström, Department of Computing Science, Umeå University - jem@cs.umu.se

FL 6: Definite Clause Grammars (kap. 7)

Föreläsning 11 i programmeringsparadigm. Negering.

Introduktion till Haskell

Introduktion till programmering SMD180. Föreläsning 4: Villkor och rekursion

Repetition C-programmering

I dag: Blockstruktur, omgivningar, problemlösning

Använda Python Laboration 1 GruDat, DD1344

Rekursiva algoritmer sortering sökning mönstermatchning

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

Föreläsning 9 Exempel. Intervallhalveringsmetoden. Intervallhalveringsmetoden... Intervallhalveringsmetoden...

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

Föreläsning [ ] i programmeringsparadigm. Om multiparadigm-språket OZ och en tjock bok.

Imperativ programmering

Labb i Datorsystemteknik och programvaruteknik Programmering av kalkylator i Visual Basic

FL 5: Aritmetik. Teori

Föreläsning 9 Exempel

Senast. Idag. Icke-strikt evaluering. Strikt evaluering. Testa latheten! Lat evaluering. Plus och minus med lat evaluering. Testa latheten!

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

Föreläsning 2 Programmeringsteknik och C DD1316. Mikael Djurfeldt

Föreläsning 5-6 Innehåll. Exempel på program med objekt. Exempel: kvadratobjekt. Objekt. Skapa och använda objekt Skriva egna klasser

Procedurer och villkor. Rekursiva procedurer. Exempel: n-fakultet

Procedurer och villkor

Föreläsning 5-6 Innehåll

Tentamen i. Programmering i språket C

Planering Programmering grundkurs HI1024 HT data

Planering Programmering grundkurs HI1024 HT 2014

Deklarativt programmeringsparadigm

Språket Python - Del 2 Grundkurs i programmering med Python

Programmering II (ID1019) :00-11:00

DD1311 Programmeringsteknik för S1 Laborationer läsåret

Funktionens deklaration

Programdesign. Dokumentera. Dokumentera

TDDC74 Lab 02 Listor, sammansatta strukturer

HI1024 Programmering, grundkurs TEN

TDDC74 Programmering, abstraktion och modellering DUGGA 2

Grafik i DrRacket AV TOMMY KARLSSON

Datastrukturer i Haskell

Några saker till och lite om snabbare sortering

kl Tentaupplägg

Transkript:

Föreläsning 10 i programmeringsparadigm. Boxmodellen för append. Jag försöker förklara denna bild 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]? 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". % 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) Körningar på en mängd olika sätt: append(+, +, 1) suffix?- 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 : 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]).?- 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]?

?- member(r, Rs). Rs = [R _A]? ; Rs = [_A,R _B]? 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]).?- 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 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 list 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. Om man programmerar i ren Prolog (pure Prolog) har allt i programmet en logisk läsning. Man rekommnderar att man börjar programmera på detta sätt och tänker på programmet med den logiska läsningen. 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 ordningen mellan delmålen i en regelkropp 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: % 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]? */

Lite Haskell: Ytterligare ett exempel på interaktiv programmering med bilder och klickningar: module Hai where -- på /afs/nada.kth.se/misc/info/progp02/haskell/hai.hs import GraphicInteract -- towers 5 körning med textutmatning import SOEGraphics -- main 5 körning med grafisk utmatning. Klicka för drag. data Peg = A B C deriving (Show, Enum) -- Icke grafiskt towers of Hai. Resultat : En lista med par -- ("Från-peg", "till-peg") towers :: Int -> Peg -> Peg -> Peg -> [(Peg, Peg)] towers 0 from to using = [] towers n from to using = towers (n-1) from using to ++ [(from, to)] ++ towers (n-1) using to from -- Grafisk version med hjälp av makegraphicinteractive. Varje klickning ett drag. -- main 3 startar med 3 brickor, main 5 startar med 5 brickor osv. main :: Int -> IO() main n = makegraphicinteractive startstatus "Hai" (topixels (wsize + 30, wsize)) (firstgraphs startstatus) f where startstatus = fixstartstatus n type StatusType = ([(Peg,Peg)],Int,(Int,[Int]),(Int,[Int]),(Int,[Int])) -- (listan generad av towers, -- antal brickor, -- tre par med (antalet brickor, brickorna) för peg A, B respektive C.) -- Brickorna betecknas med 1.. n, 1 minsta brickan fixstartstatus :: Int -> StatusType -- n ::Int antalet brickor fixstartstatus n = (towers n A B C, n, (n, [1..n]), (0, []), (0, [])) f :: StatusType -> (Int, Int) -> (StatusType, [Graphic]) f ( ((A,B):pfpts), n, (na, (a:alist)),(nb, blist),(nc, clist)) _ = (newstate, [drawdisc Black A (na-1) a n, drawdisc Yellow B nb a n]) where newstate = (pfpts, n, (na-1, alist), (nb+1, a:blist), (nc, clist)) f ( ((A,C):pfpts), n, (na, (a:alist)),(nb, blist),(nc, clist)) _ = (newstate, [drawdisc Black A (na-1) a n, drawdisc Yellow C nc a n]) where newstate = (pfpts, n, (na-1, alist), (nb, blist), (nc+1, a:clist)) f ( ((B,C):pfpts), n, (na, (alist)),(nb, b:blist),(nc, clist)) _ = (newstate, [drawdisc Black B (nb-1) b n, drawdisc Yellow C nc b n]) where newstate = (pfpts, n, (na, alist), (nb-1, blist), (nc+1, b:clist)) f ( ((B,A):pfpts), n, (na, (alist)),(nb, b:blist),(nc, clist)) _ = (newstate, [drawdisc Black B (nb-1) b n, drawdisc Yellow A na b n]) where newstate = (pfpts, n, (na+1, b:alist), (nb-1, blist), (nc, clist)) f ( ((C,B):pfpts), n, (na, (alist)),(nb, blist),(nc, c:clist)) _ = (newstate, [drawdisc Black C (nc-1) c n, drawdisc Yellow B nb c n]) where newstate = (pfpts, n, (na, alist), (nb+1, c:blist), (nc-1, clist)) f ( ((C,A):pfpts), n, (na, (alist)),(nb, blist),(nc, c:clist)) _ = (newstate, [drawdisc Black C (nc-1) c n, drawdisc Yellow A na c n]) where newstate = (pfpts, n, (na+1, c:alist), (nb, blist), (nc-1, clist)) f s _ = (s, [])

-- Grafik med autoskalning drawdisc :: Color -> Peg -> Int -> Int -> Int -> Graphic drawdisc col peg posx s n = withcolor col (polygon (map (topixels. scaledwith. (movedto peg posx n ) ) (disc s n) )) wsize :: Float wsize = 200.0 -- mm windowsize, window is square firstgraphs :: StatusType -> [Graphic] firstgraphs (_, n, (na, alist),(nb, blist),(nc, clist))= map (\i -> drawdisc Yellow A (n-i) i n ) alist ++ map (\i -> drawdisc Yellow B (n-i) i n ) blist ++ map (\i -> drawdisc Yellow C (n-i) i n ) clist pixelpermm :: Float pixelpermm = 100.0/25.4 -- pixel / mm -- pixel / mm topixels :: (Float, Float) -> (Int, Int) topixels (x, y) = (round (pixelpermm * x), round(pixelpermm * y)) disc :: Int -> Int -> [(Float, Float)] disc s n = [( - dx, 0.0), (dx, 0.0), (dx, dy), ( - dx, dy)] where dx = inttofloat s / inttofloat (2*n) dy = 4.0 / inttofloat n movedto :: Peg -> Int -> Int -> (Float, Float) -> (Float, Float) movedto peg posx n (xx, yy) = (px + xx, py + yy) where px = 1.0 + 2.0 * inttofloat (fromenum peg) py = 0.3 + (4.0 / inttofloat n)* inttofloat (n - posx - 1) scaledwith :: (Float, Float) -> (Float, Float) scaledwith (ix, iy) = (sc*ix, sc*iy) where sc = wsize/5.0 inttofloat :: Int -> Float inttofloat n = frominteger(tointeger n ) {- Main> towers 4 A B C [(A,C),(A,B),(C,B),(A,C),(B,A),(B,C),(A,C),(A,B), (C,B),(C,A),(B,A),(C,B),(A,C),(A,B),(C,B)] Main> towers 3 A B C [(A,B),(A,C),(B,C),(A,B),(C,A),(C,B),(A,B)] -}