Programkonstruktion och datastrukturer. Moment 5 Om generella datastrukturer och träd. PKD 2011/12 moment 5 Sida 1 Uppdaterad

Relevanta dokument
Programkonstruktion och datastrukturer. Moment 6 Om generella datastrukturer och träd. PKD 2012/13 moment 6 Sida 1 Uppdaterad

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 4 Om rekursion. PK1&PM1 HT-06 moment 4 Sida 1 Uppdaterad

Summera godtyckligt antal tal. Programkonstruktion. Moment 4 Om rekursion. Fullständigt resonemang för summeringen. Analys av summeringsproblemet

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 8 Om abstrakta datatyper och binära sökträd

Tabeller. Programkonstruktion. Moment 8 Om abstrakta datatyper och binära sökträd. Implementering av tabellen. Operationer på tabellen

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

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 9 Om högre ordningens funktioner. PK1&PM1 HT-06 moment 9 Sida 1 Uppdaterad

Tabeller. Programkonstruktion. Moment 8 Om abstrakta datatyper och binära sökträd. Specifikationer för tabellfunktionerna. Operationer på tabellen

Omtentamen (del 1, 6 högskolepoäng) i Programkonstruktion och datastrukturer (1DL201)

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

Programkonstruktion. Tentamen,

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

Programkonstruktion. Tentamen,

Programmeringsmetodik DV1, Programkonstruktion del 1 Tentamen,

Två fall: q Tom sekvens: () q Sekvens av element: (a b c) ; (sum-rec '(2 4 6)) = 12. q Första elementet uppfyller vissa villkor: (2 a b c)

Programkonstruktion. Tentamen,

Funktionell programmering DD1361

Programkonstruktion och datastrukturer. Formell verifiering eller hur man bevisar att program gör rätt utan att testa dem

Tentamen (del 2) (4 högskolepoäng) i Programkonstruktion och datastrukturer (1DL201)

Tentamen 1 (6 högskolepoäng) i Programkonstruktion och datastrukturer (1DL201)

Programkonstruktion. Moment 11 Om sidoeffekter In/utmatning och imperativ programmering. PKD 2011/12 moment 11 Sida 1 Uppdaterad

Programkonstruktion och Datastrukturer

Rekursiva algoritmer sortering sökning mönstermatchning

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

Tentamen, Algoritmer och datastrukturer

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

Instruktioner - Datortentamen TDDD73 Funktionell och imperativ programmering i Python

Programmering II (ID1019) :00-17:00

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

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 2 Introduktion till funktioner och programutveckling

Datastrukturer, algoritmer och programkonstruktion (DVA104, VT 2015) Föreläsning 6

Former av rekursion. Programkonstruktion. Moment 5 Mera om rekursion. Fakultetsfunktionen. Största gemensamma delare (repris!

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

Imperativ programmering. Imperativ programmering konstruktioner i Lisp. Datastrukturer (kap ) arraystruktur poststruktur

TDDC74 Programmering: Abstraktion och modellering Tentamen, onsdag 9 juni 2016, kl 14 18

Programmering II (ID1019)

Föreläsning Datastrukturer (DAT037)

Tentamen i. TDDC67 Funktionell programmering och Lisp

DD1361 Programmeringsparadigm. Carina Edlund

Träd, binära träd och sökträd. Koffman & Wolfgang kapitel 6, avsnitt 1 4

Programmering II (ID1019) :00-11:00

Tillämpad Programmering (ID1218) :00-13:00

GRUNDER I VHDL. Innehåll. Komponentmodell Kodmodell Entity Architecture Identifierare och objekt Operationer för jämförelse

Föreläsning 6: Introduktion av listor

Återanvändning av kod? Programkonstruktion. Moment 2 Introduktion till funktioner och programutveckling. Funktionsdefinitioner. Egna funktioner i ML

Föreläsning Datastrukturer (DAT036)

Innehåll. Föreläsning 12. Binärt sökträd. Binära sökträd. Flervägs sökträd. Balanserade binära sökträd. Sökträd Sökning. Sökning och Sökträd

GOTO och lägen. Några saker till och lite om snabbare sortering. GOTO och lägen (3) GOTO och lägen (2)

Några saker till och lite om snabbare sortering

TDIU01 - Programmering i C++, grundkurs

6 Rekursion. 6.1 Rekursionens fyra principer. 6.2 Några vanliga användningsområden för rekursion. Problem löses genom:

Programkonstruktion och datastrukturer. Moment 3 Rekursion och listor. PKD 2012/13 moment 3 Sida 1 Uppdaterad

SCB :-0. Uno Holmer, Chalmers, höger 2 Ex. Induktiv definition av lista. // Basfall

Instruktioner - Datortentamen TDDD73 Funktionell och imperativ programmering i Python TDDE24 Funktionell och imperativ programmering del 2

Programkonstruktion och. Datastrukturer

Repetition i Python 3. Exemplen fac. Exemplen fac motivering. Exemplen fac i Python

Föreläsningsanteckningar, Introduktion till datavetenskap HT S4 Datastrukturer. Tobias Wrigstad

FÖRELÄSNING 2, TDDC74, VT2018 BEGREPP PROBLEMLÖSNING MED HJÄLP AV FALLANALYS PROBLEMLÖSNING MED HJÄLP AV REKURSION

Instruktioner - Datortentamen TDDD73 Funktionell och imperativ programmering i Python

Idag: Dataabstraktion

Lösningar Datastrukturer TDA

Inom datalogin brukar man använda träd för att beskriva vissa typer av problem. Om man begränsar sig till träd där varje nod förgrenar sig högst två

F11 - Rekursion. ID1004 Objektorienterad programmering Fredrik Kilander

Textsträngar från/till skärm eller fil

BINÄRA TRÄD. (X = pekarvärdet NULL): struct int_bt_node *pivot, *ny; X X X 12 X X 12 X X -3 X X

Omgivningar. Omgivningar är viktiga eftersom de avgör vilka namn som är synliga och därmed dessas innebörd och de värden som är förknippade med dem.

Programmering II (ID1019) :00-11:00

Abstrakta datatyper. Primitiva vektorer. Deklarera en vektor

TDDC74 Programmering, abstraktion och modellering. Tentamen

Att förstå hur man konstruerar modulära program Att kunna skapa nya funktioner Att förstå hur data skickas mellan funktioner

Metodanrop - primitiva typer. Föreläsning 4. Metodanrop - referenstyper. Metodanrop - primitiva typer

Linjärt minne. Sammanhängande minne är ej flexibelt. Effektivt

Föreläsning 8 Datastrukturer (DAT037)

TDIU01 - Programmering i C++, grundkurs

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Övningsuppgifter #11, Programkonstruktion och datastrukturer

Föreläsning 7 Innehåll. Rekursion. Rekursiv problemlösning. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursion. Rekursivt tänkande:

Pythons standardbibliotek

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Föreläsning 9 Datastrukturer (DAT037)

Sätt att skriva ut binärträd

Procedurer och villkor

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

Dugga Datastrukturer (DAT036)

Inledande programmering med C# (1DV402) 27+15=42 1 (22)

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

Föreläsning 5. Rekursion

Programmering II (ID1019) :00-12:00

Föreläsning 7: Syntaxanalys

Datastrukturer i kursen. Föreläsning 8 Innehåll. Träd rekursiv definition. Träd

TDDC74 Lab 04 Muterbara strukturer, omgivningar

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

TDDI16 Datastrukturer och algoritmer. Algoritmanalys

Datastrukturer, algoritmer och programkonstruktion (DVA104, HT 2014) Föreläsning 5

Programmering II (ID1019) :00-12:00

DD1320 Tillämpad datalogi. Lösning (skiss) till tenta 20 okt 2011

TDDC74 Programmering, abstraktion och modellering DUGGA 2

TDIU01 Programmering i C++

Obligatorisk uppgift 5

MMA132: Laboration 2 Matriser i MATLAB

Transkript:

Programkonstruktion och datastrukturer Moment 5 Om generella datastrukturer och träd PKD 2011/12 moment 5 Sida 1 Uppdaterad 2011-11-22

Sammanblandning av representerade data I en tillämpning behöver man använda koder för veckodagar, t.ex. 1 måndag, 2 tisdag, etc. För att göra programmet mera lättläst och oberoende av de specifika koderna namnger man dem (definitionsabstraktion): val Mon = 1; (* Monday *) val Tue = 2; (* Tuesday *) val Wed = 3; (* Wednesday *) etc Koderna är nu tal och de går att räkna med (Wed*2), men de representerar egentligen veckodagar, som inte skall gå att räkna med. ML blir i praktiken otypat vad beträffar tal och veckodagar. PKD 2011/12 moment 5 Sida 2 Uppdaterad 2011-11-22

Vad definitionsabstraktion inte kan göra Felaktiga mönster: Hopblandning av data: (* weekend d (* overtimepay(d,x) TYPE: int->bool TYPE: int*int->int PRE: d är en korrekt dag PRE: d är en korrekt dag. POST: true om d är en POST: Timlönen veckodagen veckoslutsdag (lö/sö), d med hänsyn false annars *) till övertid om grundtimlönen är x. *) fun weekend Sat = true ajaj... weekend Sun = true ajaj... fun overtimepay(d,x) = weekend _ = false; ujuj... if weekend d then d * 2 ujuj... Felaktigt värde: weekend(8) ojoj... else x; Sat, Sun är identifierare vilka som helst de binds i mönster. PKD 2011/12 moment 5 Sida 3 Uppdaterad 2011-11-22

Uppräkningstyper datatype weekday = Mon Tue Wed Thu Fri Sat Sun; weekday blir en helt ny datatyp med de angivna värdena. (* weekend d (* overtimepay(d,x) TYPE: weekday->bool TYPE: weekday*int->int PRE: (inget) Obs! PRE: (inget) Obs! POST: true om d är en POST: Timlönen veckodagen veckoslutsdag (lö/sö), d med hänsyn false annars *) till övertid om grundtimlönen är x. *) fun weekend Sat = true Ok! weekend Sun = true Ok! fun overtimepay(d,x) = weekend _ = false; if weekend d then Felaktigt värde: d * 2 else Typfel! weekend(8) Typfel! x; Sat, Sun är värden som true, false de binds inte i mönster. PKD 2011/12 moment 5 Sida 4 Uppdaterad 2011-11-22

Konvertering av uppräkningstyper datatype weekday = Mon Tue Wed Thu Fri Sat Sun; ML definierar ingen speciell ordning av värdena i weekday. Inte heller finns något inbyggt sätt att omvandla dem till/från heltal som man t.ex. kan med tecken (ord, chr). Sådant får man göra själv... (* daynumber d (* numberday n TYPE: weekday->int TYPE: int->weekday PRE: (inget) PRE: 1 <= n <= 7 POST: ordningstalet POST: veckodagen med för veckodagen d *) ordningstal n *) fun daynumber Mon = 1 fun numberday 1 = Mon daynumber Tue = 2 numberday 2 = Tue daynumber Wed = 3 numberday 3 = Wed daynumber Thu = 4 numberday 4 = Thu daynumber Fri = 5 numberday 5 = Fri daynumber Sat = 6 numberday 6 = Sat daynumber Sun = 7; numberday 7 = Sun numberday _ = raise Domain; PKD 2011/12 moment 5 Sida 5 Uppdaterad 2011-11-22

Vissa inbyggda typer kan definieras datatype bool = true false; datatype unit = (); Dessa datatyper är fördefinierade i ML och kan inte definieras igen, men de fungerar som om de definierats på detta sätt. PKD 2011/12 moment 5 Sida 6 Uppdaterad 2011-11-22

Sammanblandning av representerade data Rationella tal (se exempel tidigare i kursen) har speciella egenskaper och borde ha en egen typ. Ex.vis. heltalsvektorer (punkter i rutnät eller matriser) representeras också naturligt som int*int-tupler likadant som rationella tal. Fastän datastrukturen är samma är egenskaperna helt annorlunda.t.ex. utförs addition av vektorer komponentvis (1,2) + (1,3) = (2,5). 5 4 3 2 1 0 0 1 2 3 ML-program blir i praktiken otypade beträffande dessa sorters data. Risk för sammanblanding: addition av vektorer med qadd eller blandning av rationella tal och vektorer. PKD 2011/12 moment 5 Sida 7 Uppdaterad 2011-11-22

Konstruerade (taggade) typer Med deklarationen datatype kan man skapa nya typer som skiljer sig från alla andra: datatype intvec = Intvec of int*int; datatype rational = Q of int*int; intvec och rational är nu helt nya datatyper som båda innehåller en int*int-tupel men som har en etikett (tag) som skiljer dem åt. Värden av typen intvec skrivs föregångna av konstruktorn Intvec, t.ex. Intvec(1,2). Samma med rationella tal, t.ex. Q(1,2). Jämför konstruktorn :: som skapar en listcell. PKD 2011/12 moment 5 Sida 8 Uppdaterad 2011-11-22

Användning av konstruerade typer Man kan betrakta en värde av en konstruerad datatyp som ett kuvert med konstruktorn påskriven, i vilken man har stoppat ned de data som ingår i värdet. Q (1,2) Försök att blanda ihop en heltalsvektor och ett rationellt tal ger typfel eftersom ML kan se på konstruktorerna att de hör till olika typer. Intvec och Q har funktionstyper: Intvec:int*int->intvec Q:int*int->rational och ser ut och kan användas som funktioner men är inte funktioner i vanlig mening eftersom de inte utför någon beräkning. De skapar ett nytt värde på samma sätt som den infixa konstruktorn ::. PKD 2011/12 moment 5 Sida 9 Uppdaterad 2011-11-22

Användning av konstruerade typer För att komma åt delarna i ett värde av en konstruerad typ måste de tas ut ur kuvertet. För detta använder man matchning på liknande sätt som man matchar på listceller med ::. Nya värden av konstruerad typ kan skapas genom att ge uttryck som beräknas som argument till konstruktorn. (* qadd(x,y) TYPE: rational*rational->rational PRE: x och y skall vara korrekta rationella tal (dvs nämnaren skall vara 0). POST: Summan av x och y EX: qadd(q(1,2),q(1,3)) = Q(5,6) *) fun qadd(q(p1,q1),q(p2,q2)) = Q(p1*q2+p2*q1,q1*q2); PKD 2011/12 moment 5 Sida 10 Uppdaterad 2011-11-22

Typsystemet förhindrar sammanblandning > qadd(q(1,2),q(1,3)); val it = Q (5,6) : rational - qadd(intvec(1,2),intvec(1,3)); Error-Type error in function application. Function: qadd : rational * rational -> rational Argument: (Intvec(1,2),Intvec(1,3)):intvec*intvec Reason: Can't unify rational with intvec (Different type constructors) Found near qadd (Intvec (1, 2), Intvec (1,...)) PKD 2011/12 moment 5 Sida 11 Uppdaterad 2011-11-22

Alternativa former för konstruerade typer Formerna hos datatype-deklarationen för uppräkningstyper och konstruerade typen kan kombineras! datatype number = Int of int Real of real; Ett värde i number är antingen ett heltal med etiketten Int eller ett flyttal med etiketten Real. Tack vare att etiketten skiljer kan man alltid veta om det handlar om ett heltal eller ett flyttal. Användning: Om man vill ha värden med olika form (utseende). Om man vill ha funktioner som kan ha olika typer som argument eller värde. (Namnet Int ovan är valt av mig för att vara likt int, men det finns ingen koppling mellan dem i ML. Samma gäller Real och real.) PKD 2011/12 moment 5 Sida 12 Uppdaterad 2011-11-22

Kombinerade typer Typen number kan innehålla ett heltal eller ett flyttal. Vid addition av number konverteras termerna automatiskt till flyttal om det behövs. (* toreal n TYPE: number -> number POST: Talet n konverterat till flyttal EX: toreal (Int 30) = Real 30.0 *) fun toreal (Real r) = Real r toreal (Int i) = Real (real i); (* addnumbers(x,y) TYPE: number*number->number POST: summan av x och y, heltal konverteras till flyttal om det behövs. EX: addnumbers(int 30, Real 2.0) = Real 32.0 *) fun addnumbers(int x, Int y) = Int (x+y) addnumbers(x,y) = let val Real xr = toreal x; val Real yr = toreal y in Real (xr+yr) end; PKD 2011/12 moment 5 Sida 13 Uppdaterad 2011-11-22

Exempel: Representation av fordon Vi definierar en datatyp för att beskriva olika fordon. Vi anger för: bilar: reg.beteckning, färg och motorstyrka cyklar: färg och hjuldiameter skateboard: färg datatype vehicle = Car of string*string*int Bicycle of string*int Skateboard of string; Olika värden av typen vehicle: Car("XYZ123","green",100) Bicycle("red",26) Skateboard "silver" PKD 2011/12 moment 5 Sida 14 Uppdaterad 2011-11-22

Exempel: räkna fordon av viss färg (* vehiclecolour vehicle TYPE: vehicle->string POST: Färgen hos vehicle. EX: vehiclecolour(bicycle("green",24)) = "green" *) fun vehiclecolour (Car(_,colour,_)) = colour vehiclecolour (Bicycle(colour,_)) = colour vehiclecolour (Skateboard colour) = colour; (* countcolourvehicles(colour,vehicles) TYPE: string*vehicle list->int POST: antal fordon i vehicles med färgen colour. EX: countcolourvehicles("green", [Car("XYZ123","green",100),Skateboard "silver", Bicycle("green",24)]) = 2 *) (* VARIANT: length vehicles *) fun countcolourvehicles(_,[]) = 0 countcolourvehicles(colour,vehicle::rest) = (if vehiclecolour vehicle = colour then 1 else 0)+ countcolourvehicles(colour,rest); PKD 2011/12 moment 5 Sida 15 Uppdaterad 2011-11-22

Intern dokumentation av datatyper Inte bara funktioner utan också konstruerade datatyper behöver dokumenteras. Varje datatype skall förses med en kommentar liknande en funktionsspecifikation som har två delar: En beskrivning av hur data är representerat Datastrukturinvarianten datatype rational = Q of int*int; (* REPRESENTATION CONVENTION: Ett rationellt tal representeras som Q(t,n) där t är täljaren och n är nämnaren. REPRESENTATION INVARIANT: Nämnaren får inte vara 0. *) PKD 2011/12 moment 5 Sida 16 Uppdaterad 2011-11-22

Polymorfa datatyper En eller flera komponentdatatyper i en konstruerad datatyp kan vara en typvariabel: datatype 'a option = NONE SOME of 'a option blir här en typkonstruktor precis som list och vector. Instansen int option är en typ med två slags värden: Konstanten NONE. Ett heltal taggat med konstruktorn SOME. Exempel på värden av typen int option: NONE, SOME 4, SOME ~2, SOME 0 Exempel på värden av typen string option: NONE, SOME "Hej", SOME "", SOME "ABC" PKD 2011/12 moment 5 Sida 17 Uppdaterad 2011-11-22

Användning av option option är en inbyggd typkonstruktor i ML. Den används t.ex. när man vill ha ett bättre sätt att hantera felsituationer i programmet än att avbryta körningen eller göra något odefinierat. (* sumuptoopt n Type: int->int option Post: SOME s, där s är summan av talen 0...n om n>=0. NONE annars. Ex: sumuptoopt 4 = SOME 10, sumuptoopt ~2 = NONE *) (* Variant: n *) fun sumuptoopt n = if n < 0 then NONE else if n = 0 then SOME 0 else SOME(n+valOf(sumUpToOpt(n-1))); Förvillkor saknas jämför med defensiva sumupto i kursmoment 4! (valof är en inbyggd funktion i ML: fun valof(some x) = x) PKD 2011/12 moment 5 Sida 18 Uppdaterad 2011-11-22

Rekursiva typer Komponenterna i en konstruerad datatyps värde får höra till datatypen själv! (En rekursiv typ.) En listcell head tail cons-cell kan definieras som en konstruerad datatyp som innehåller en tupel med två komponenter för head resp. tail: datatype 'a list = [] :: of 'a*'a list; Listor i ML fungerar exakt som om de var definierade med denna deklaration. (Man kan inte göra om deklarationen för att prova ML tillåter inte att man gör en ny deklaration av listor.) PKD 2011/12 moment 5 Sida 19 Uppdaterad 2011-11-22

Träd Listor kan representera data med linjär struktur t.ex. förteckningar och sekvenser. Ofta har dock data trädstruktur, t.ex. i ett släktträd: delträd rot gren noder Mattias Annika Lars-Henrik Yvonne Karl-Gustaf Birgit Sverker Detta är ett binärt träd varje nod har maximalt två grenar. Löv är noder som saknar grenar. Roten är trädets början. Djupet hos en nod är avståndet till roten. löv Martin PKD 2011/12 moment 5 Sida 20 Uppdaterad 2011-11-22

Hur representera ett träd? (Dålig lösning) Varje nod läggs i en lista tillsammans med delträdens rotnoder: [("Mattias","Annika","Lars-Henrik"), ("Annika", "Yvonne", "Karl-Gustaf"), ("Yvonne", "", ""), ("Karl-Gustaf", "", ""), ("Lars-Henrik", "Birgit", "Sverker"), ("Sverker", "", "Martin"), ("Birgit", "", ""), ("Martin", "", "")] : (string*string*string) list + Enkel representation Navigering i trädet kräver sökning i listan. Hur hitta farfar? Vilken nod är rotnoden? Uppdatering av trädet kräver också sökning. Denna representation är inte bra i praktiken! PKD 2011/12 moment 5 Sida 21 Uppdaterad 2011-11-22

Träddatatyper Binära träd kan representeras direkt i ML som en rekursiv datatyp! datatype familytree = Empty Person of string*familytree*familytree; Mattias Annika Lars-Henrik Yvonne Karl-Gustaf Birgit Sverker Martin Person("Mattias", Person("Annika",Person("Yvonne",Empty,Empty), Person("Karl-Gustaf",Empty,Empty)), Person("Lars-Henrik",Person("Birgit",Empty,Empty), Person("Sverker",Empty, Person("Martin", Empty,Empty)))) PKD 2011/12 moment 5 Sida 22 Uppdaterad 2011-11-22

Enkel navigering (* farfar t TYPE: familytree -> familytree PRE: Det finns en farfader till rotnoden i t. POST: Delträdet till t där farfadern är rotnod. EX: farfar (Person("Mattias",..., Person("Lars-Henrik",..., Person("Sverker",...,...)))) = Person("Sverker",...,...) *) fun farfar(person(_,_,person(_,_,ff))) = ff; PKD 2011/12 moment 5 Sida 23 Uppdaterad 2011-11-22

Rekursion över träd Rekursion över träd är normalt dubbel rekursion man måste göra rekursion över båda grenarna från en given nod. (* countpersons t TYPE: familytree -> int PRE: (inget) POST: Antal personer i trädet t EX: countpersons( Person("Ronja",Person("Lovis",Empty,Empty), Person("Mattis",Empty,Empty))) = 3 *) (* VARIANT: Antal noder i trädet t *) fun countpersons Empty = 0 countpersons(person(_,left,right)) = 1 + countpersons Left + countpersons Right; PKD 2011/12 moment 5 Sida 24 Uppdaterad 2011-11-22

Rekursion över träd (forts.) fun countpersons Empty = 0 countpersons(person(_,left,right)) = 1 + countpersons Left + countpersons Right; countpersons(person("ronja",person("lovis",empty,e mpty), Person("Mattis",Empty,Empty))) > 1+countPersons(Person("Lovis",Empty,Empty)+ countpersons(person("mattis",empty,empty)) > 1+(1+countPersons Empty+countPersons Empty)+ countpersons(person("mattis",empty,empty)) > 1+(1+0+countPersons Empty)+ countpersons(person("mattis",empty,empty)) > 1+(1+countPersons Empty)+ countpersons(person("mattis",empty,empty)) > 1+(1+0)+countPersons > 2+countPersons(Person("Mattis",Empty,Empty)) > 2+(1+countPersons Empty+countPersons Empty) > 3 PKD 2011/12 moment 5 Sida 25 Uppdaterad 2011-11-22

Syntaxträd Strukturen hos en formel kan beskrivas med ett syntaxträd. 3+2*x-1 : + 1 datatype expr = Const of int Var of string Plus of expr*expr Minus of expr*expr Times of expr*expr Div of expr*expr; Minus(Plus(Const 3,Times(Const 2,Var "x")), Const 1) PKD 2011/12 moment 5 Sida 26 Uppdaterad 2011-11-22 3 2 * x

Beräkning av uttryck (utan variabler) (* eval(expr) TYPE: expr->int PRE: expr innehåller inga variabler. POST: Värdet av expr. Ex: eval(minus(plus(const 3, Times(Const 2,Const 4)), Const 1)) = 10 *) (* VARIANT: Storleken hos expr. *) fun eval(const c) = c eval(plus(e1,e2)) = eval e1 + eval e2 eval(minus(e1,e2)) = eval e1 - eval e2 eval(times(e1,e2)) = eval e1 * eval e2 eval(div(e1,e2)) = eval e1 div eval e2; Vi återkommer till variabler i syntaxträdet senare PKD 2011/12 moment 5 Sida 27 Uppdaterad 2011-11-22

Beräkning av uttryck (forts.) fun eval(const c) = c eval(plus(e1,e2)) = eval e1 + eval e2 eval(minus(e1,e2)) = eval e1 - eval e2 eval(times(e1,e2)) = eval e1 * eval e2 eval(div(e1,e2)) = eval e1 div eval e2; eval(minus(plus(const 3,Times(Const 2,Const 4)),Const 1)) > eval(plus(const 3,Times(Const 2,Const 4))) - eval(const 1) > (eval(const 3)+eval(Times(Const 2,Const 4))))- eval(const 1) > (3+eval(Times(Const 2,Const 4))))-eval(Const 1) > (3+(eval(Const 2)*eval(Const 4)))-eval(Const 1) > (3+(2*eval(Const 4)))-eval(Const 1) > (3+(2*4))-eval(Const 1) > (3+8)-eval(Const 1) > 11-eval(Const 1) > 11-1 > 10 PKD 2011/12 moment 5 Sida 28 Uppdaterad 2011-11-22

Teologiska fakulteten Hum.-Sam. vetenskapsområdet Juridiska fakulteten Allmänna träd Uppsala universitet... Språkvet. fakulteten Inst. för IT... Tek.-Nat. vetenskapsområdet Tek.-Nat. fakulteten Inst. för matematik... Inst. för teknikvet. datatype 'a tree = Tree of 'a*('a tree) list; 'a är typen för informationen i varje nod. PKD 2011/12 moment 5 Sida 29 Uppdaterad 2011-11-22

Exempel på träd datatype 'a tree = Tree of 'a*('a tree) list; Tree("Uppsala universitet", [Tree("Hum.-Sam. vetenskapsområdet", [Tree("Teologiska fakulteten",[]), Tree("Juridiska fakulteten",[]), Tree("Språkvet. fakulteten",[]),...]), Tree("Tek.-Nat. vetenskapsområdet", [Tree("Tek.-Nat. fakulteten"), [Tree("Inst. för IT",[]), Tree("Inst. för matematik",[]), Tree("Inst. för teknikvet.",[]),...])]),...]) : string tree PKD 2011/12 moment 5 Sida 30 Uppdaterad 2011-11-22

Minns ni analysen av summeringsproblemet? För att summera talen från 0 till n kan jag lösa det enklare problemet att summera från 0 till n-1 och sedan lägga till n! Om n=0 kan jag direkt säga att summan är 0. fun sumupto 0 = 0 sumupto n = sumupto(n-1) + n sumupto 3 > sumupto(3-1)+3 > sumupto 2+3 >(sumupto(2-1)+2)+3 > (sumupto 1+2)+3 > ((sumupto(1-1)+1)+2)+3 > ((sumupto 0+1)+2)+3 > ((0+1)+2)+3 > (1+2)+3 > 3+3 > 6 PKD 2011/12 moment 5 Sida 31 Uppdaterad 2011-11-22

En annan analys av summeringsproblemet Start. Låt summan vara 0. Är n=0? Ja. Stopp. Nej. Addera n till summan. Subtrahera 1 från n. Konstruktionen kallas för en loop. Här adderar vi det största talet först (n+...+0) och inte det minsta (0+...+n), men det ger samma resultat. (I detta fall!!) PKD 2011/12 moment 5 Sida 32 Uppdaterad 2011-11-22

Iteration i ML Basfall fun sumupto n = sumuptoaux(n,0) Rekursivt anrop fun sumuptoaux(0,sum) = sum sumuptoaux(n,sum) = sumuptoaux(n-1,sum+n) En hjälpfunktion sumuptoaux implementerar loopen. Tekniken kallas iteration (svansrekursion) och är ett specialfall av rekursion. Argumentet sum kallas för ackumulator. Obs att nya värden för n och sum beräknas samtidigt. sumupto 2 > sumuptoaux(2,0) > sumuptoaux(2-1,0+2) > sumuptoaux(1,2) > sumuptoaux(1-1,2+1) > sumuptoaux(0,3) > 3 PKD 2011/12 moment 5 Sida 33 Uppdaterad 2011-11-22

Bindningar i iteration fun sumuptoaux(0,sum) = sum sumuptoaux(n,sum) = sumuptoaux(n-1,sum+n) sumuptoaux(2,0) > sumuptoaux(n-1,sum+n)[n >2,sum >0] > sumuptoaux(2-1,sum+n)[n >2,sum >0] > sumuptoaux(1,sum+n) [n >2,sum >0] > sumuptoaux(1,0+n) [n >2,sum >0] > sumuptoaux(1,0+2) [n >2,sum >0] > sumuptoaux(1,2) [n >2,sum >0] > sumuptoaux(n-1,sum+n)[n >1,sum >2] [n >2,sum >0] skuggas bort helt > sumuptoaux(1-1,sum+n)[n >1,sum >2] > sumuptoaux(0,sum+n) [n >1,sum >2] > sumuptoaux(0,2+n) [n >1,sum >2] > sumuptoaux(0,2+1) [n >1,sum >2] > sumuptoaux(0,3) [n >1,sum >2] > 3 PKD 2011/12 moment 5 Sida 34 Uppdaterad 2011-11-22

Funktionsspecifikationen för sumuptoaux sumuptoaux(n,sum) Type: int*int->int För att rekursionen skall terminera krävs att n inte är mindre än 0: Pre: n>=0 Man kan inte kräva sum=0. Det gäller inte för de rekursiva anropen! Eftervillkoret är inte att sumuptoaux summerar talen 0 till n. Så är den avsedd att användas men det är inte vad den faktiskt gör. Post: Summan av sum och talen från 0 till n. Exempel behövs också... Ex.: sumuptoaux(3,0) = 6 sumuptoaux(4,5) = 15 sumuptoaux(0,2) = 2 Rekursionsvarianten anges som del av programdokumentationen. Variant: n PKD 2011/12 moment 5 Sida 35 Uppdaterad 2011-11-22

Minnesbehov Rekursion i allmänhet behöver minne i proportion till antalet rekursiva anrop eftersom en del av beräkningen väntar. sumupto 3 > sumupto(3-1)+3 > sumupto 2+3 >(sumupto(2-1)+2)+3 > (sumupto 1+2)+3 > ((sumupto(1-1)+1)+2)+3 > ((sumupto 0+1)+2)+3 > ((0+1)+2)+3 > (1+2)+3 > 3+3 > 6 Uttrycket blir hela tiden större... Programmet kan få slut på minne om de rekursiva anropen är många och/eller kräver mycket minne. PKD 2011/12 moment 5 Sida 36 Uppdaterad 2011-11-22

Minnesbehov vid iteration Iteration har konstant minnesåtgång. fun sumupto n = sumuptoaux(n,0); fun sumuptoaux(0,sum) = sum sumuptoaux(n,sum) = sumuptoaux(n-1,sum+n) sumupto 3 > sumuptoaux(3,0) > sumuptoaux(3-1,0+3) > sumuptoaux(2,0) > sumuptoaux(2-1,3+2) > sumuptoaux(1,2) > sumuptoaux(1-1,5+1) > sumuptoaux(0,6) > 6 Minnet kan aldrig ta slut (inte pga rekursionen i alla fall). PKD 2011/12 moment 5 Sida 37 Uppdaterad 2011-11-22

Beräkningsordning i rekursion fun foo [] = [] foo(first::rest) = first::foo rest; foo plockar isär en lista men sätter genast ihop den igen! foo [1,2,3,4] = [1,2,3,4] Vad händer om man gör samma sak iterativt? fun revaux([],ack) = ack revaux(first::rest,ack) = revaux(rest,first::ack); fun rev l = revaux(l,[]); Låt oss se rev [1,2,3,4] = [4,3,2,1] revaux gör beräkningen i omvänd ordning jämfört med foo! PKD 2011/12 moment 5 Sida 38 Uppdaterad 2011-11-22

Vänd på en lista (körexempel) fun revaux([],ack) = ack revaux(first::rest,ack) = revaux(rest,first::ack) fun rev l = revaux(l,[]) rev [1,2,3,4] > revaux([1,2,3,4],[]) > revaux([2,3,4],[1]) > revaux([3,4],[2,1]) > revaux([4],[3,2,1]) > revaux([],[4,3,2,1]) > [4,3,2,1] (rev är en inbyggd funktion i ML för att vända på listor.) PKD 2011/12 moment 5 Sida 39 Uppdaterad 2011-11-22

Kodningsmönster för iteration Flödesschema för funktionen foo: Kod för funktionen foo: Start. A. Ja. T? C. Stopp. Nej. B. fun foo x = fooaux A fun fooaux x = if T then C else fooaux B Iterativa program är i vissa fall de bästa, men i allmänhet blir programmen lättare att skriva och förstå med vanlig rekursion! PKD 2011/12 moment 5 Sida 40 Uppdaterad 2011-11-22

Ett mindre snyggt program (* notwins l TYPE: ''a list -> ''a list POST: l med alla följder av samma element ersatta av en enda förekomst. EX: notwins [1,2,2,3,4,4,4] = [1,2,3,4] *) (* VARIANT: length l *) fun notwins [] = [] notwins [x] = [x] notwins (first::rest) = if first = hd rest then notwins rest else first::notwins rest; Här skulle man vilja ha ett mönster som delar upp svansen av argumentet ytterligare så att man inte behöver använda hd. PKD 2011/12 moment 5 Sida 41 Uppdaterad 2011-11-22

Ett till mindre snyggt program för samma sak (Samma funktionsspecifikation.) fun notwins [] = [] notwins [x] = [x] notwins (first::second::rest) = if first = second then notwins(second::rest) else first::notwins(second::rest); Svansen av argumentet är nu uppdelad i second och rest, men då måste man sätta ihop dem igen i de rekursiva anropen! PKD 2011/12 moment 5 Sida 42 Uppdaterad 2011-11-22

Mönstret as Med konstruktionen as kan man både binda en datastruktur och matcha den mot ytterligare mönster. fun notwins [] = [] notwins [x] = [x] notwins (first::(rest as second::_)) = if first = second then notwins rest else first::notwins rest; I tredje klausulen kommer svansen på argumentet dels bindas till rest. dels matchas vidare mot mönstret second::_ Då behöver man varken använda hd eller sätta ihop det man redan tagit isär. PKD 2011/12 moment 5 Sida 43 Uppdaterad 2011-11-22