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

Relevanta dokument
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

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

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

Programkonstruktion. Tentamen,

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

Programkonstruktion. Tentamen,

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

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

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

SI-möte #10, Programkonstruktion och Datastrukturer

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

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)

DD1361 Programmeringsparadigm. Carina Edlund

Programkonstruktion. Tentamen,

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

Programmeringsmetodik DV1, Programkonstruktion del 1 Tentamen,

Programmering II (ID1019) :00-17:00

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

Programkonstruktion och Datastrukturer

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

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

Tentamen i. TDDC67 Funktionell programmering och Lisp

Övningsuppgifter #11, Programkonstruktion och datastrukturer

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

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

"Referentiell transparens"

Föreläsning 5 i programmeringsparadigm.

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

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

Programmering II (ID1019) :00-11:00

TDIU01 - Programmering i C++, grundkurs

Programmering II (ID1019) :00-12:00

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

Sätt att skriva ut binärträd

TDIU01 - Programmering i C++, grundkurs

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

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

Rekursiva algoritmer sortering sökning mönstermatchning

Programmering II (ID1019) :00-12:00

Föreläsning 13. Rekursion

Exempeltenta GruDat 2002/2003

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

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

Introduktion till formella metoder Programmeringsmetodik 1. Inledning

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

Programmering för Språkteknologer II. Innehåll. Associativa datastrukturer. Associativa datastrukturer. Binär sökning.

String [] argv. Dagens Agenda. Mer om arrayer. Mer om arrayer forts. String [] argv. argv är variabelnamnet. Arrayer och Strängar fortsättning

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

Programmering II (ID1019) :00-11:00

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

Sökning och sortering

Föreläsning 4 Datastrukturer (DAT037)

TDDC74 Programmering, abstraktion och modellering. Tentamen

Föreläsning 7: Syntaxanalys

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

Korsordlösare Sara Hedbrandh Strömberg Programkonstruktion VT 10 Inlämninsguppgift

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

Föreläsning 3-4 Innehåll. Diskutera. Metod. Programexempel med metod

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

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

Idag: Par och listor. Symboler. Symboler används för att uttrycka icke-numeriska data såsom namn, adress, bilregisternummer, boktitel, osv.

TDDC74 Programmering, abstraktion och modellering DUGGA 2

Idag: Par och listor. Scheme. DA2001 (Föreläsning 6) Datalogi 1 Hösten / 29

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

n Detta för att kunna koncentrera oss på n Tal: number? n Symboler: symbol? n Strängar: string? n Tecken: char? n Boolskt: boolean?

Funktionell programmering DD1361

Signalflödesmodellen. Två (gamla) exempel: Kvadratera alla jämna löv.

Pascal... Pascal. Pascal... Pascal...

Föreläsning 3-4 Innehåll

Sökning och sortering

Sökning och sortering. Sökning och sortering - definitioner. Sökning i oordnad lista. Sökning med vaktpost i oordnad lista

Pascal. reserverade ord fördefinierade funktioner och procedurer egendefinierade funktioner, procedurer och objekt

Dekomposition och dynamisk programmering

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

Programmering A. Johan Eliasson

public static void mystery(int n) { if (n > 0){ mystery(n-1); System.out.print(n * 4); mystery(n-1); } }

MATLAB. Python. Det finns flera andra program som liknar MATLAB. Sage, Octave, Maple och...

Arrayer (vektorer) Murach s: kap Elektronikcentrum i Svängsta AB

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

Procedurer och villkor

Uppgift 1 ( Betyg 3 uppgift )

Föreläsning 6: Introduktion av listor

I ett program hantera man ofta samlingar av objekt av samma typ.

Namn: (Ifylles av student) Personnummer: (Ifylles av student) Tentamensdatum: Tid: Hjälpmedel: Inga hjälpmedel

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

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

TDDC77 Objektorienterad Programmering

Tommy Färnqvist, IDA, Linköpings universitet

Instruktioner - Datortentamen TDDD73 Funktionell och imperativ programmering i Python

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

Inlämningsuppgift MiniPlotter

Datatyper och kontrollstrukturer. Skansholm: Kapitel 2) De åtta primitiva typerna. Typ Innehåll Defaultvärde Storlek

Datalogi, grundkurs 1

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

Programmering II (ID1019) :00-12:00

TDDC74 Lab 02 Listor, sammansatta strukturer

Föreläsning 5 Innehåll

Objektorienterad programmering

TDDC74 Lab 04 Muterbara strukturer, omgivningar

Transkript:

Programkonstruktion och datastrukturer Moment 9 Om högre ordningens funktioner PKD 2011/12 moment 9 Sida 1 Uppdaterad 2012-01-15

Anonyma funktioner igen En funktion som inte är namngiven kallas för en anonym funktion. formellt argument fn x => x+1 funktionskropp När man anropar funktionen så beräknas funktionskroppen som om x bytts ut mot argumentet i anropet. x är bunden i funktionen. x är en godtycklig identifierare. Funktionens typ bestäms av typen hos det formella argumentet och funktionskroppen. Funktionen ovan har typen int -> int. (fn x => x+1)(4*2) - > (fn x => x+1) 8 - > 8+1 - > 9 PKD 2011/12 moment 9 Sida 2 Uppdaterad 2012-01-15

Funktioner är första klassens objekt i ML Kom ihåg att funktioner kan behandlas som datastrukturer i ML. Funktioner kan vara argument till andra funktioner Värdet av en funktion kan också vara en funktion Funktioner kan förekomma som delar av datastrukturer (t.ex. element i listor). PKD 2011/12 moment 9 Sida 3 Uppdaterad 2012-01-15

Funktioner kan vara argument fun dotwice(f,x) = f(f x); fun square x = x*x; dotwice(square,3) - > square(square 3) - > square(3*3) - > square 9 - > 9*9 - > 81 dotwice(fn x=>x+1,3) - > (fn x=>x+1)((fn x=>x+1) 3) - > (fn x=>x+1)(3+1) - > (fn x=>x+1) 4 - > 4+1 - > 5 Vilken är typen av dotwice? (Prova gärna genom att skriva in definitionen i ML.) En första ordningens funktion har argument som inte är funktioner. En högre ordningens funktion har något funktionsargument. PKD 2011/12 moment 9 Sida 4 Uppdaterad 2012-01-15

merge sort igen 7 1 5 7 3 2 12 8 split 7 5 3 12 1 7 2 8 mergesort mergesort 3 5 7 12 1 2 7 8 merge 1 2 3 5 7 7 8 12 PKD 2011/12 moment 9 Sida 5 Uppdaterad 2012-01-15

Varför är inte merge sort polymorf > fun sort [] = [] # sort [x] = [x] # sort xs = # let # val (ys, zs) = split xs # in # merge(sort ys, sort zs) # end; val sort = fn : int list -> int list Algoritmen för merge sort bryr sig inte om vilken typ det är på de data man sorterar. Så varför är inte funktionen sort polymorf? PKD 2011/12 moment 9 Sida 6 Uppdaterad 2012-01-15

Original-merge 3 5 7 12 1 2 7 8 merge 1 2 3 5 7 7 8 12 (* merge(l,m) TYPE: int list*int list -> int list PRE: L och M är sorterade i stigande ordning. POST: Listan L@M med elementen i stigande ordning. EX.: merge([3,5,7,12],[1,2,7,8]) = [1,2,3,5,7,7,8,12] *) (* VARIANT: (length l1)*(length l2) *) fun merge ([], M) = M merge (L, []) = L merge (L as x::xs, M as y::ys) = if x > y then y :: merge (L, ys) else x :: merge (xs, M); PKD 2011/12 moment 9 Sida 7 Uppdaterad 2012-01-15

Polymorf merge (* merge(less,l,m) TYPE: ('a*'a->bool)*'a list*'a list -> 'a list PRE: less är en ordningsrelation. L och M är sorterade i stigande ordning enligt less. POST: Listan L@M med elementen i stigande ordning enligt relationen less. EX.: merge(op <,[3,5,7,12],[1,2,7,8]) = [1,2,3,5,7,7,8,12] *) (* Variant: (length L)*(length M) *) fun merge(_, [], M) = M merge(_, L, []) = L merge(less, L as x::xs, M as y::ys) = if less(y,x) then y :: merge(less,l,ys) else x :: merge(less,xs,m); PKD 2011/12 moment 9 Sida 8 Uppdaterad 2012-01-15

Notationen op Funktioner som är infixa operatorer kan inte direkt vara argument: > merge(<,[3,5,7,12],[1,2,7,8]); Warning-(<) has infix status but was not preceded by op. ML förväntar sig argument före och efter <. Lösning: skriv op före <. op stänger av den speciella syntaktiska betydelsen hos <. > merge(op <,[3,5,7,12],[1,2,7,8]); val it = [1, 2, 3, 5, 7, 7, 8, 12] : int list Varning: foo(op *) gör inte vad man tror. Åtgärd: foo(op * ) blank Varför? (Fast just Poly/ML är snäll när det gäller dessa saker.) PKD 2011/12 moment 9 Sida 9 Uppdaterad 2012-01-15

Polymorf merge sort (* polysort(less,l) TYPE: ('a*'a->bool)*'a list -> 'a list PRE: less är en ordningsrelation POST: En lista med alla element i L i stigande ordning enligt less. EXAMPLE: polysort(op <,[5,7,3,12,1,7,2,8,13]) = [1,2,3,5,7,7,8,12,13] *) (* VARIANT: length L *) fun polysort(_,[]) = [] polysort(_,[x]) = [x] polysort(less,xs) = let val (ys, zs) = split xs in merge(less,polysort(less,ys), polysort(less, zs)) end; PKD 2011/12 moment 9 Sida 10 Uppdaterad 2012-01-15

Mer komplicerade relationer Sortera en lista av namn uttryckta som efternamn-förnamn-par: val namnlista = [("Bergkvist","Erik"),("Andersson","Arne"), ("Björklund","Henrik"),("Eriksson","Lars-Henrik"), ("Andersson","Petra"),("Berg","Stina")]; När kommer ett namn före ett annat? Efternamnet skall jämföras först! fun lessname((e1:string,f1:string),(e2,f2)) = e1 < e2 orelse e1 = e2 andalso f1 < f2; Varför behövs typdeklarationerna (:string)? polysort(lessname,namnlista) = [("Andersson","Arne"),("Andersson","Petra"), ("Berg","Stina"),("Bergkvist","Erik"), ("Björklund","Henrik"),("Eriksson","Lars-Henrik")] PKD 2011/12 moment 9 Sida 11 Uppdaterad 2012-01-15

Värdet av en funktion kan vara en funktion fun selectopr s = case s of "plus" => op + "minus" => op - "times" => op * "div" => op div "sumto" => sumrange "mean" => fn (x,y) => (x+y) div 2; (sumrange(i,n) summerar heltalen från i till n.) selectopr "plus" - > op + selectopr "mean" - > fn (x,y) => (x+y) div 2 (selectopr "plus") (4,6) - > (op +)(4,6) - > 10 (selectopr "sumto") (4,6) - > sumrange(4,6) - > 15 Vilken är typen hos selectopr? PKD 2011/12 moment 9 Sida 12 Uppdaterad 2012-01-15

Diverse om användning av funktionsvärden Funktionsapplikation i ML är vänsterassociativ. Ett uttryck som (f x) y kan lika gärna skrivas f x y. ML kan inte skriva ut funktionsvärden. Funktionsvärden ersätts med symbolen fn. > selectopr "plus"; val it = fn : int * int -> int Typen för selectopr är string->(int*int->int). Typkonstruktorn -> är högerassociativ så vi kan i detta fall ta bort parenteserna och skriva: string->int*int->int. PKD 2011/12 moment 9 Sida 13 Uppdaterad 2012-01-15

Lite annorlunda syntaxträd Operatorn lagras i ett fält i varje nod. 3+2*x-1 : + 1 datatype expr = Const of int Var of string Op of string*expr*expr; Op("minus",Op("plus",Const 3, Op("times",Const 2,Var "x")), Const 1) 3 2 * x PKD 2011/12 moment 9 Sida 14 Uppdaterad 2012-01-15

Beräkning av uttryck selectopr används för att välja funktion givet informationen om operator i trädet. (* eval(expr,table) TYPE: expr*(string*int) list->int PRE: Alla variabler i expr finns i table. Ingen division med 0 förekommer i expr. POST: Värdet av expr uträknat. EX: eval(op("minus", Op("plus",Const 3, Op("times",Const 2,Var "x")), Const 1), insert([],"x",4)) = 10 *) (* VARIANT: Storleken hos expr *) fun eval(const c, _) = c eval(var v, values) = search(values,v) eval(op(opr, e1, e2),values) = selectopr opr (eval(e1,values),eval(e2,values)); PKD 2011/12 moment 9 Sida 15 Uppdaterad 2012-01-15

Tabell med funktionsvärden I stället för att använda selectopr för att välja funktion kan vi skapa en tabell som kopplar operatorerna i trädet till ML-funktioner. val optable = [("plus", op +), ("minus", op -), ("times", op * ), ("div", op div), ("sumto", sumrange), ("mean", fn (x,y) => (x+y) div 2)]; Vilken typ har optable? PKD 2011/12 moment 9 Sida 16 Uppdaterad 2012-01-15

Beräkning av uttryck med funktionstabell search används för att hitta avsedd funktion givet informationen om operator i trädet. (* eval(expr,table) TYPE: expr*(string*int) list->int PRE: Alla variabler i expr finns i table. Ingen division med 0 förekommer i expr. POST: Värdet av expr uträknat. EX: eval(op("minus", Op("plus",Const 3, Op("times",Const 2,Var "x")), Const 1), insert([],"x",4)) = 10 *) (* VARIANT: Storleken hos expr *) fun eval(const c, _) = c eval(var v, values) = search(values,v) eval(op(opr, e1, e2),values) = search(optable,opr) (eval(e1,values),eval(e2,values)); PKD 2011/12 moment 9 Sida 17 Uppdaterad 2012-01-15

Syntaxträd med funktioner i noderna Själva ML-funktionen som skall utföra beräkningen lagras i ett fält i varje nod. 3+2*x-1 : + 1 datatype expr = Const of int Var of string Op of (int*int->int)*expr*expr; Op(op -,Op(op +,Const 3, Op(op *,Const 2,Var "x")), Const 1) PKD 2011/12 moment 9 Sida 18 Uppdaterad 2012-01-15 3 2 * x

Beräkning med funktioner i noderna Nu behövs ingen översättning utan ML-funktionen kan anropas direkt! (* eval(expr,table) TYPE: expr*(string*int) list->int PRE: Alla variabler i expr finns i table. Ingen division med 0 förekommer i expr. POST: Värdet av expr uträknat. EX: eval(op(op -, Op(op +,Const 3, Op(op *,Const 2,Var "x")), Const 1), insert([],"x",4)) = 10 *) (* VARIANT: Storleken hos expr *) fun eval(const c, _) = c eval(var v, values) = search(values,v) eval(op(opr, e1, e2),values) = opr(eval(e1,values),eval(e2,values)); PKD 2011/12 moment 9 Sida 19 Uppdaterad 2012-01-15

Mönster vid listrekursion fun squarelist [] = [] squarelist (first::rest) = square first::squarelist rest; fun neglist [] = [] neglist (first::rest) = ~first::neglist rest; Dessa funktioner har samma struktur de skiljer sig bara i funktionsnamnen och de rödmarkerade delarna. Man kan skriva en högre ordningens funktion mapl som fångar strukturen abstraherar bort skillnaderna och som har ett funktionsargument för skillnaden: fun mapl(f,[]) = [] mapl(f,first::rest) = f first::mapl(f,rest); fun squarelist l = mapl(square,l); fun neglist l = mapl(~,l); PKD 2011/12 moment 9 Sida 20 Uppdaterad 2012-01-15

Mönster vid listrekursion (forts.) fun mapl(f,[]) = [] mapl(f,first::rest) = f first::mapl(f,rest); fun squarelist l = mapl(square,l); squarelist [1,~2,4] - > mapl(square,[1,~2,4]) - > square 1::mapl(square,[~2,4]) - > 1*1::mapl(square,[~2,4]) - > 1::mapl(square,[~2,4]) - > 1::square ~2::mapl(square,[4]) - > 1:: ~2* ~2::mapl(square,[4]) - > 1::4::mapl(square,[4]) - > 1::4::square 4::mapl(square,[]) - > 1::4::4*4::mapl(square,[]) - > 1::4::16::mapl(square,[]) - > 1::4::16::[] = [1,4,16] PKD 2011/12 moment 9 Sida 21 Uppdaterad 2012-01-15

Stuvade funktioner fun plus(x,y) = x+y; (plus: int*int->int) fun plus' x = fn y => x+y; (plus': int->int->int) plus(4,6) > 4+6 > 10 plus' 4 6 > (fn y => 4+y)6 > 4+6 > 10 plus' är en stuvad (curried efter H.B. Curry) form av plus. plus' tar ett argument i taget. Funktionen som är värdet av plus' minns bindningen av x. val add1 = plus' 1; (add1 nu bunden till fn y => 1+y) add1 3 > (fn y => 1+y)3 > 1+3 > 4 fun har en speciell form för att definiera stuvade funktioner: fun plus' x y = x+y; är samma definition av plus' som den ovan. PKD 2011/12 moment 9 Sida 22 Uppdaterad 2012-01-15

Beräkning av funktioner En stuvad form av mapl finns inbyggd i ML under namnet map. mapl(f,l) = map f l fun squarelist l = map square l; map kan också användas för att beräkna funktionen squarelist: val squarelist = map square; PKD 2011/12 moment 9 Sida 23 Uppdaterad 2012-01-15

Beräkning av specialiserade sorteringsfunktioner Antag att vi skrev om den polymorfa polysort som en stuvad funktion med typ ('a*'a->bool) -> 'a list -> 'a list Då går det lätt att göra specialversioner för olika typer: > val sortint = polysort op <; val sortint = fn : int list -> int list > sortint [5,7,3,12,1,7,2,8,13]; val it = [1,2,3,5,7,7,8,12,13] : int list > val sortname = polysort lessname; val sortname = fn : (string * string) list -> (string * string) list > sortname namnlista; val it = [("Andersson","Arne"),("Andersson","Petra"),("Berg ","Stina"), ]: (string * string) list PKD 2011/12 moment 9 Sida 24 Uppdaterad 2012-01-15

Mer komplicerade programmönster fun length [] = 0 length (first::rest) = 1+length rest; fun addlist [] = 0 addlist (first::rest) = first+addlist rest; fun append([],y) = y append(first::rest,y) = first::append(rest,y); Gemensamt för dessa: En operation utförs på första elementet av listan och resultatet av det rekursiva anropet (blått). Det finns ett bestämt värde ( startvärde ) vid basfallet (rött). Att length passar in i mönstret syns bättre om man skriver så här: length (first::rest) = (fn (x,y) => 1+y)(first,length rest); PKD 2011/12 moment 9 Sida 25 Uppdaterad 2012-01-15

Funktionen foldr Den inbyggda funktionen foldr utför mer generell rekursion över listor än map. foldr kan utläsas som fold from right. (* foldr f e l TYPE: ('a*'b->'b) -> 'b -> 'a list -> 'b PRE: (ingen) POST: f(x1,f(x2,...f(xn,e)...)) om l=[x1,x2,...,xn] *) (* VARIANT: längden av l *) fun foldr f e [] = e foldr f e (first::rest) = f(first,foldr f e rest); PKD 2011/12 moment 9 Sida 26 Uppdaterad 2012-01-15

Beräkning av funktioner med foldr fun foldr f e [] = e foldr f e (first::rest) = f(first,foldr f e rest); Vad är värdet av foldr (op +) 0? f binds till (op +) och e binds till 0. Resultatet blir alltså en funktion som är definierad som: fun foo [] = 0 foo (first::rest) = (op +)(first,foo rest);...vilket (utom syntaxen) är den rekursiva definitionen av addlist. (Den beräknade funktionen är anonym jag har kallat den för foo.) addlist kan alltså definieras som: val addlist = foldr (op +) 0; eller kanske lite tydligare fun addlist l = foldr (op +) 0 l; PKD 2011/12 moment 9 Sida 27 Uppdaterad 2012-01-15

Användning av foldr Exempel på användning av foldr: fun length l = foldr (fn (x,y) => 1+y) 0 l; fun addlist l = foldr (op +) 0 l; fun append(x,y) = foldr (op ::) y x; fun smallest (first::rest) = foldr Int.min first rest; fun split l = foldr (fn (first,(x,y)) => (first::y,x)) ([],[]) l; map kan definieras med hjälp av foldr: fun map f l = foldr (fn (x,y) => f x::y) [] l; PKD 2011/12 moment 9 Sida 28 Uppdaterad 2012-01-15

Funktionen foldl Det finns också en inbyggd funktion för iteration (svansrekursion) över listor: (* foldl f e l TYPE: ('a*'b->'b) -> 'b -> 'a list -> 'b POST: f(xn,...f(x2,f(x1,e))...) om l=[x1,x2,...,xn] *) (* VARIANT: längden av l *) fun foldl f e l = let fun foldlaux([],ack) = ack foldlaux(first::rest,ack) = foldlaux(rest,f(first,ack)) in foldlaux(l,e) end; Exempel: fun rev l = foldl (op ::) [] l; PKD 2011/12 moment 9 Sida 29 Uppdaterad 2012-01-15

Funktionen filter List.filter kan användas för att välja ut vissa delar av en lista. T.ex. List.filter (fn x => x>0) [1,~2,4,0] = [1,4] (* filter p l TYPE: ('a -> bool) -> 'a list -> 'a list POST: En lista av de element i l som gör p sann *) (* VARIANT: längden av l *) fun filter p [] = [] filter p (first::rest) = if p first then first::filter p rest else filter p rest; filter kan även definieras med hjälp av foldr: fun filter p l = foldr (fn (x,y) => if p x then x::y else y) [] l PKD 2011/12 moment 9 Sida 30 Uppdaterad 2012-01-15

Högre ordningens funktioner för vektorer I biblioteket Vector finns varianter av funktionerna map, foldr och foldl som arbetar på vektorer i stället för listor. Exempel: Summera heltal i en vektor (svansrekursivt): (* sumvector a TYPE: int vector -> int POST: Summan av elementen i a *) fun sumvector a = Vector.foldl (op +) 0 a; Exempel: Bilda en lista av elementen i en vektor: (* tolist a TYPE: 'a vector -> 'a list POST: En lista av elementen i vektorn a. *) fun tolist a = Vector.foldr (op ::) [] a; > sumvector (Vector.fromList [18,12,~5,12,10]); val it = 47 : int PKD 2011/12 moment 9 Sida 31 Uppdaterad 2012-01-15

Funktionell programmering och multiprocessorer Hastighetsökningen vid utveckling av datorer bygger i dag huvudsakligen på att datorerna kan göra flera beräkningar samtidigt (t.ex. flerkärniga processorer) än att varje enskild beräkning går snabbare. För att utnyttja detta måste program skrivas så att de ingående beräkningarna kan fördelas på flera processorer. Detta är svårt. Eftersom beräkningsordningen inte spelar roll i funktionell programmering kan olika delberäkningar i ett funktionellt program delas upp på olika processorer och utföras samtidigt. I ML görs beräkningarna från vänster till höger, men det är inget principiellt krav. I det följande exemplet avviker vi när det behövs. PKD 2011/12 moment 9 Sida 32 Uppdaterad 2012-01-15

Exempel: parallelisering Antag att vi har ett problem där en och samma operation skall utföras på en mängd olika data och man sedan skall kombinera resultatet på något sätt. Sådana problem lämpar sig väl för uppdelning på olika processorer, men hur skall man skriva programmen så att det blir möjligt? Ett exempel kan vara att ifrån en samling med textdokument (lagrade som strängar) söka ut precis de dokument som innehåller en given sträng. Sökningarna kan göras i flera dokument samtidigt på olika processorer PKD 2011/12 moment 9 Sida 33 Uppdaterad 2012-01-15

Exempel: mapreduce För att uttrycka detta definierar vi funktionen mapreduce som är en kombination av map och foldr. (* mapreduce r m e l TYPE: ('a->'b)->('b*'c->'c)->'c->'a list->'c PRE: (ingen) POST: r(m x1,r(m x2,...r(m xn,e)...)) om l=[x1,x2,...,xn] *) (* VARIANT: längden av l *) fun mapreduce r m e [] = [] mapreduce r m e (x::l) = r(m x,mapreduce r m e l); PKD 2011/12 moment 9 Sida 34 Uppdaterad 2012-01-15

Exempel: findstring Vi behöver en funktion för att söka i ett dokument... (* findstring'(s,x,pos) TYPE: string*string*pos->bool PRE: 0 pos size x-size s POST: true om s är en delsträng av x vid eller eller efter position pos, false annars EXAMPLE: findstring("bc","abcd",1) = true findstring("bc","abcd",2) = false *) (* VARIANT: size x - pos *) fun findstring'(s,x,pos) = pos + size s <= size x andalso (String.substring(x,pos,size s)=s orelse findstring'(s,x,pos+1)); (* findstring(s,x) TYPE: string*string->bool PRE: (ingen) POST: true om s är en delsträng av x, false annars EXAMPLE: findstring("bc","abcd") = true findstring("bb","abcd") = false *) fun findstring(s,x) = findstring'(s,x,0); PKD 2011/12 moment 9 Sida 35 Uppdaterad 2012-01-15

Exempel: checkdoc En hjälpfunktion... (* checkdoc(s,doc) TYPE: string*string->string list PRE: (ingen) POST: [x] om s är en delsträng av x, annars [] EXAMPLE: checkdoc("bc","abcd") = ["abcd"] checkdoc("bc","abbd") = [] *) fun checkdoc(s,doc) = if findstring(s,doc) then [doc] else []; PKD 2011/12 moment 9 Sida 36 Uppdaterad 2012-01-15

Exempel: searchdocuments Så till sist huvudfunktionen... (* searchdocuments(s,l) TYPE: string*string list->string list PRE: (ingen) POST: En lista av de element i l som innehåller s som delsträng. EXAMPLE: searchdocuments("bc",["abcd","abbd"])= ["abcd"] *) fun searchdocuments(s,docs) = mapreduce (op @) (fn doc => checkdoc(s,doc)) [] docs; PKD 2011/12 moment 9 Sida 37 Uppdaterad 2012-01-15

searchdocuments: hur funkar det? searchdocuments("bc",["abcd","abbd"]) > mapreduce op @ (fn x => ) [] ["abcd","abbd"] > (fn x => ) "abcd" @ mapreduce op @ (fn x => ) [] ["abbd"] > checkdoc("bc","abcd") @ mapreduce op @ (fn x => ) [] ["abbd"] Här väljer vi att inte ta vänstraste uttrycket först! > checkdoc("bc","abcd") @ (fn x => ) "abbd" @ mapreduce op @ (fn x => ) [] [] > checkdoc("bc","abcd") @ checkdoc("bc","abbd")@ mapreduce op @ (fn x => ) [] [] inte här heller! > checkdoc("bc","abcd")@checkdoc("bc","abbd")@[] Anropen av checkdoc kan i princip utföras samtidigt! > ["abcd"] @ [] @ [] > ["abcd"] PKD 2011/12 moment 9 Sida 38 Uppdaterad 2012-01-15

Googles MapReduce Den här idén ligger bakom Googles programmeringsmetod MapReduce som de använder för att köra program med massiva parallellberäkningar på hundratusentals processorer. Se t.ex. Wikipediaartikeln om MapReduce! PKD 2011/12 moment 9 Sida 39 Uppdaterad 2012-01-15