2009-11-06 Lennart Edblom, Inst. f.
datavetenskap 1
F6: Högre ordningens funktioner
• Mönster för rekursion
• Partiellt applicerbara funktioner
• Anonyma funktioner
• Op
• HOF på listor
• Sortering
• Listreduktion
• Funktionskomposition
Mönster för rekursion (1)
• Rekursivt anrop i lokal deklaration. Speciellt användbart när resultatet av det rekursiva anropet ska
"bearbetas" (ex delas upp) på nåt sätt.
• Ex: Dela upp en heltalslista i två listor, tal <0 och >=0 fun split [] = ([],[])
| split (x::xs) =
let val (small,large) = split xs in if x<0 then (x::small,large)
else (small,x::large)
end;
2009-11-06 Lennart Edblom, Inst. f.
datavetenskap 2
Mönster för rekursion (1b)
• Det rekursiva anropet av huvudfunktionen använder resultatet av bearbetning av första elementet.
• fun f(y,x::xs) = let val (a,b)=help(x,y) in f(y+a, (tl xs)@[b])
end;
2009-11-06 Lennart Edblom, Inst. f.
datavetenskap 3
Mönster för rekursion (2)
• Rekursivt anrop i "huvudfunktionskroppen". T ex när bearbetningen av de olika listelementen är (nästan) oberoende av varann.
• Ex: Givet en lista på studenter (string list), returnera en lista av tripler (pnr, namn, #poäng). Funktionerna get_kurslist, get_pnr och sumpoints finns givna.
fun studlist [] = []
| studlist (name::rest)=
let val kurslista = get_kurslist(name) val pnr = get_pnr(name)
in
(pnr, name, sumpoints(kurslista)):: studlist rest end;
2009-11-06 Lennart Edblom, Inst. f.
datavetenskap 4
Mönster för rekursion (2b)
• En hjälpfunktion som returnerar ett sammansatt resultat till huvudfunktionen
local
fun help x= let val a=…
val b=…
val c=…
in (a,b,c) end;
in
fun main (y::ys) = let (a1,b1,c1)= help y
in … a1 … b1 … c1 … main ys … end end;
2009-11-06 Lennart Edblom, Inst. f.
datavetenskap 5
Högre Ordningens Funktioner
• Högre ordningens funktioner?
Funktioner som kan ta funktioner som argument
Funktioner som kan ge en funktion som resultat
• Partiellt applicerabara funktioner
”Funktionen som fullvärdig medlem i språket”
6
7
Partiellt applicerbara funktioner
• Ex: skatteberäkning. Min skatt i kronor beror på a) skatteprocenten; b) min lön
fun tax1 tax = (*En funktion som tar en skattesats och returnerar en ny funktion som tar min lön och beräknar skatten. En ”skattetabell” *);
fun tax2 loen = (tax1 UmeaSkatt) loen;
• Precis så kan man resonera i ML, men kombinera tax1 och tax2 i en funktion
Partiellt applicerbara funktioner
- fun taxdue tax wage = wage*tax div 100;
> val taxdue = fn: int->(int->int)
• taxdue tar en int som parameter och returnerar en funktion av typ int-> int
• (taxdue 40) är en funktion som tar en parameter wage och beräknar wage*40 div 100
• taxdue kan appliceras partiellt, på bara en parameter, för att skapa en ny funktion
- val tax20 = taxdue 20;
> val tax20: fn:int->int - tax20 10000;
> val it=2000:int
2009-11-06 Lennart Edblom, Inst. f.
datavetenskap 8
”Template” för PA funktioner
• Generellt mönster för deklaration av högre ordningens (PA) funktioner:
fun fname pat11 pat12 …pat1n = exp1 | fname pat21 pat22 …pat2n = exp2 | ………
| fname patk1 patk2 …patkn = expk
• Samma effekt som en funktion med n parametrar, men kan appliceras partiellt.
• Exempel: Kolla om lista1 är ett prefix av lista2 fun starts1 [ ] _ = true
| starts1 _ [ ] = false
| starts1 (h1::t1)(h2::t2) = h1=h2 andalso starts1 t1 t2
• PA funktioner är en delmängd av HOF
2009-11-06 Lennart Edblom, Inst. f.
datavetenskap 9 10
Map
• Map tar inte bara en funktion som parameter, men är också partiellt applicerbar.
- fun map f [] = []
| map f (x::xs)=(f x)::(map f xs);
val map=fn: (’a->’b) -> ’a list -> ’b list
sq : int->int
map sq : int list -> int list floor: real->int
map floor: real list -> int list
11
Anonyma funktioner
• Ett funktionsvärde kan existeras utan att namnges.
Nyckelordet fn används - fn n=>2*n;
> val it=fn:int->int - (fn n=>2*n) 3;
> val it=6:int
• Generellt utseende fn pattern1 => expression1 | pattern2 => expression2 …
| patternN => expressionN
12
Anonyma funktioner
• När ett funktionsvärde av denna typ appliceras på ett argument v matchas v mot mönstren, detta motsvarar evaluering av
case v of pattern1 => expression1 | pattern2 => expression2 …
| patternN => expressionN
13
Anonyma funktioner
• Följande par av deklarationer är inbördes ekvivalenta - val CircleArea= fn r => Math.pi*r*r;
- fun CircleArea r = Math.pi*r*r;
> val CircleArea = fn:real->real
- val f =fn(a,b)=> a*b;
- fun f(a,b)= a*b;
> val f = fn:int*int->int
- val f=fn a=>(fn b=>a*b);
- fun f a b=a*b;
> val f = fn:int->int->int
14
rec
• Följande definition fungerar ej:
val fact= fn 0=>1 | n=>n*fact(n-1);
• Vi måste använda nyckelordet rec för en rekursiv definition
val rec fact= fn 0=>1
| n=>n*fact(n-1);
15
mappning
• Anonyma funktioner kan med fördel ”mappas” på listor mm.
• Ex:
fun poslist []=[]
| poslist (x::xs)=x>0::poslist xs;
är ekvivalent med
fun poslist lst=map (fn x=> x>0) lst;
eller
val poslist = map (fn x=> x>0);
16
op
• Infixa funktioner (på par) kan användas i prefix notation genom nyckelordet op.
op +;
val it=fn:int*int->int (op +) (2,3);
val it=5:int;
fun addElems [] = []
| addElems ((x,y)::zs) = (x+y)::addElems zs;
är ekvivalent med
val addElements = map (op +);
17
HOF på listor
• map
är en HOF på listor
• Filter: Ta fram alla element med en viss egenskap. Givet ett villkor, gå igenom listan och behåll de element som uppfyller villkoret
-fun filter p []=[]
| filter p (x::xs)=if p x then x::filter p xs
else filter p xs;
> val filter = fn:(‘a->bool)->(‘a list->’a list) - filter (fn n=> n mod 2 = 0) [1,2,3,4,5,6,7];
> val it = [2,4,6]:int list
18
HOF på listor
• Filter finns i biblioteket List, liksom ett antal andra nyttiga funktioner som tex:
exists kollar om det finns ett element i en lista som uppfyller ett predikat
val exists= fn:(‘a->bool)->‘a list->bool
all kollar om alla element i en lista uppfyller ett predikat
val all = fn:(‘a->bool)->‘a list->bool
partition delar upp en lista i två (beroende på en predikatfunktion) (jfr unzip)
val partition =
fn:(‘a->bool)->’a list ->(‘a list * ‘a list)
19
Sortering
• Insättningssortering
• Ta ut första elementet ur listan, sortera resten av listan och sätt in det första elementet på rätt ställe
local
fun insert x [] =[x]
| insert x (y::ys)=if x<y then x::y::ys else y::(insert x ys) in
- fun sort []=[]
| sort (x::xs)=insert x (sort xs) end;
> val sort=fn: ’’a list-> ’’a list
20
Quicksort
• Välj ett element (tex första), dela upp listan i element som är större än det valda och de som är mindre. Sortera delarna och lägg sedan ihop dem.
fun quick []=[]
| quick [x]=[x]
| quick (x::xs)=
let val small = filter (fn y=>y<=x) xs val large = filter (fn y=>y>x) xs in quick small @ [x] @ quick large
end;
21
foldr / foldl (överkurs)
• Listreduktion, ex summan av en lista
• Effekten av foldr (även kallad reduce) kan beskrivas som att vi sätter in ⊗ mellan varje element i listan
• x1 ⊗ x2 ⊗ … ⊗ xn ⊗ id
• Med prefix funktionsapplikation kan samma sak beskrivas som
• ⊗ x1 (⊗ x2 (… (⊗ xn id) …))
• Elementen i listan summeras från höger till vänster.
(stackrekursiv)
22
foldr
- fun sum xs = foldr (op +) 0 xs;
> val sum = fn: int list -> int;
- sum [1,3,5,7]
> val it = 16:int
- val sum=foldr (op +) 0;
> val sum=fn:int list->int
23
foldl
• Vi kan också definiera en ”syskon-funktion” till foldr som reducerar från vänster till höger.
foldl f id [x1,x2, ,xn]=
f(xn, …f(x2,f(x1,id))…)
foldl och foldr är utbytbara endast om den funktion som distribueras är kommutativ
Jämför (1+(2+(3+0))) och (3+(2+(1+0)))
Exempel
• Ex: logiskt and (foldl / foldr spelar ej roll) - fun andlist lst =
foldl (fn(a,b) => a andalso b) true lst;
- andlist [true, true, true];
> val it = true:bool
• Exempel: insättningssortering - fun insert (x,[]) = [x]
| insert (x,(y::ys)) = if x<y then x::y::ys else y::insert (x,ys);
- val sort = foldl insert [];
> val sort = fn : int list -> int list - sort [5, 8, 4, 9, 2, 1, 8, 7];
> val it = [1, 2, 4, 5, 7, 8, 8, 9] : int list
2009-11-06 Lennart Edblom, Inst. f.
datavetenskap 24
25
Funktionskomposition
• Applicera en funktion på resultatet av en funktionsapplikation, ex sin(cos x)
• f(g(x)) kan skrivas som (f o g) x infix 3 o;
fun (f o g) x=f(g(x));
• x har samma typ som domäntypen hos g
• g x har samma typ som domäntypen hos f
• Resultatet har samma typ som resultattypen hos f f:’a->’b
g:’c->’a x:’c
o:(’a->’b)*(’c->’a)->’c->’b
26
Funktionskomposition
sqrt o real;
val it=fn:int->real
(sqrt o real) 16;
val it=4.0:real
• o är fördefinierad i ML