1 Mönstermatchning och rekursion Nr 4
Jan 25, 2016
1
Mönstermatchning och rekursion
Nr 4
2
Förenklad notation
val fnname = fn name => expression
• Förenklas tillfun fnname name = expression
• Exempelfun tax sum = sum * 25 div 100
> val tax = fn : int -> int
fun sq (x:int) = x * x
> val sq = fn : int -> int
3
Flera steg
- val taxdue = fn sum => fn tax => sum * tax div 100
- fun taxdue sum = fn tax => sum * tax div 100
- fun taxdue sum tax = sum * tax div 100
> val taxdue = fn : int -> int -> int
- val compose = fn f => fn g => fn x => f (g x)
- fun compose f = fn g => fn x => f (g x)
- fun compose f g = fn x => f (g x)
- fun compose f g x = f (g x)
> compose = fn : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
4
Droppa parenteser
• Funktionsapplikation associerar till vänster– f a b c = ((f a) b) c- twice sq 3> 81 : int
- sq sq 3;! Toplevel input:
! sq sq 3;
! ^^
! Type clash: expression of type
! int -> int
! cannot have type
! Int
- sq (sq 3);
> 81 : int
5
Villkorsuttryck
• I beräkningar behöver vi möjlighet att välja olika resultat beroende på argumentens värde. if expression1 then expression2 else expression3
– expression1 måste returnera ett boolesk värde
– expression2 och expression3 måste returnera värden av samma typ
• Om expression1 evalueras till true är värdet av hela uttrycket värdet av expression2.
• Om expression1 evalueras till false är värdet av hela uttrycket värdet av expression3.
6
Exempel
- fun abs x = if x >= 0 then x else ~x> val abs : int -> int- fun toupper c = if c >= "a" andalso c <= "z" then chr (ord c - (ord "a" - ord "A")) else c> val toupper = fn : string -> string- toupper "c";> "C" : string- toupper "å";> "å" : string
7
Mönstermatchning
• Låter oss jämföra argumentet med en mall ett mönster. Utseendet på argumentet får avgöra vilken väg som ska väljas.
• Ett alternativ till villkorssatser• Hjälper programmeraren att kontrollera att alla fall
hanteras• Ett sätt att dekonstruera (plocka isär) sammansatta
värden• Ökar läsbarheten hos många program
8
En funktion med flera alternativ mönster
fn pattern1 => expression1
| pattern2 => expression2
: :
| patternN => expressionN
• Till att börja med kan ett mönster (patterni ) vara antingen en konstant eller en variabel eller en tuppel.
• Alla mönster måste ha samma typ och uttrycken måste returnera samma typ.
9
Evaluering
• När en funktion anropas jämförs (matchas) argumentets värde mot mönstren ett i taget– Om mönstret är en konstant så matchar bara samma värde
– Om mönstret är en variabel matchar alla värden och variabeln binds till värdet.
– Om mönstret är en tuppel måste argumentvärdet också vara det och varje del i tuppeln matchas på samma sätt
• Sedan evalueras motsvarande uttryck.
10
Förenklad form
val name = fn pattern1 => fkn_body1
| pattern2 => fkn_body2
: :
| patternN => fkn_bodyN
• Motsvararfun name pattern1 = fkn_body1
| name pattern2 = fkn_body2
: : :
| name patternN = fkn_bodyN
11
Exempel
fun not x = if x (* = true *) then false else true;val not = fn : bool -> bool
fun not true = false | not false = trueval not = fn : bool -> bool
fun zero 0 = true | zero n = false> val zero = fn : int -> bool
12
Strängar
fun past "stand" = "stood" | past "swim" = "swam" | past "eat" = "ate" | past v = v ^ "ed"val past = fn : string -> string
- past "eat";> "ate" : string- past "talk";> "talked" : string
13
Mer strängar
fun change "red" = "red & yellow" | change "red & yellow" = "green" | change "green" = "yellow" | change "yellow" = "red" | change s = "illegal light: "^s> val change = fn : string -> string
- twice change "red";> "green" : string- change "blue";> "illegal light: blue" : string
14
Undantag
• För att avbryta beräkningar- 1 div 0;uncaught exception Div
• Egen definierade undantagexception name
• Använda undantagraise name
15
Exempel
exception Illegal_lightexception Illegal_lightfun change "red" = "red & yellow" | change "red & yellow" = "green" | change "green" = "yellow" | change "yellow" = "red" | change s = raise Illegal_light> val change = fn : string -> string
- change "blue";uncaught exception Illegal_light
16
Wildcard
• Namnlös parameter• När den formella parametern inte används kan man
ersätta den med Wildcard som skrivs som "_".• Wildcard matchar alla värden men det sker ingen
bindning till argumentet.fun zero 0 = true | zero _ = false
• Använd för att markera att en parameter inte används i funktionskroppen.
17
Matcha flera variabler
val And = fn false => (fn false => false | true => false) | true => (fn false => false | true => trueval And = fn : bool -> bool -> bool
fun And false false = false | And false true = false | And true false = false | And true true = true
fun And false _ = false | And true b = b
18
Rekursion
• Att upprepa en beräkning• Rekursion bygger på att en funktion anropar sig själv,
det skapar nya instanser av de bundna variablerna med nya värden.
• För rekursion krävs ett basfall som inte anropar funktionen och minst ett rekursivt fall.
• Basfallet kan ofta beskrivas med mönster t ex en heltalskonstant
19
Rekursion över Naturliga tal (0 1 2 3 4 …)
• Basfall är ofta 0 och det rekursiva fallet för positiva heltal.
• För att göra något n gånger:– för 0 gånger : gör det inte
– för n gånger : gör det en gång sedan gör det (n-1) gånger
fun fnname 0 = base_case | fnname n = recursive case using fname (n-1)
20
Exempel
fun sum 0 = 0 | sum n = n + sum (n-1)> val sum = fn : int -> int
sum 4 ==>
4 + sum (4-1) ==>
4 + sum 3 ==>
4 + (3 + sum 2) ==>
4 + (3 + (2 + sum 1)) ==>
4 + (3 + (2 + (1 + sum 0))) ==>
4 + (3 + (2 + (1 + 0))) ==> 10
21
2 upphöjt till n
fun power2 0 = 1 | power2 n = 2 * power2 (n-1)val power2 = fn : int -> int
power2 3 ==>
2 * (power2 2) ==>
2 * (2 * (power2 1)) ==>
2 * (2 * (2 * (power2 0))) ==>
2 * (2 * (2 * 1)) ==> 8
22
x upphöjt till n
• Abstrahera ut 2 och få x upphöjt till nfun power x 0 = 1 | power x n = x * power x (n-1)val power = fn : int -> int -> int
val power2 = power 2val power2 = fn : int -> int
23
Generaliserad summa
• Summan av kvadraten av alla tal mellan 0 och nfun sumsq 0 = 0 | sumsq n = sq n + sumsq (n-1)val sumsq = fn : int -> int
sumsq 3 ==>sq 3 + sumsq 2 ==> 9 + sumsq 2 ==> 9 + (sq 2 + sumsq 1) ==> 9 + (4 + sumsq 1) ==> 9 + (4 + (sq 1 + sumsq 0)) ==> 9 + (4 + (1 + sumsq 0)) ==> 9 + (4 + (1 + 0)) ==> 14
24
Fler fall
• Summan av dubbla värde av alla tal mellan 0 och nfun double n = 2 * nfun sumdouble 0 = 0 | sumdouble n = double n + sumdouble (n-1)
• Generalisera : ersätt double och sq med namnet f
• Abstrahera: låt f vara en formell parameterfun sumfunc f 0 = 0 | sumfunc f n = f n + sumfunc f (n-1)
25
Specialisera
• Specialisera för att få de tidigare funktionernafun id x = xval sum = sumfunc idval sumsq = sumfunc sqval sumdouble = sumfunc double
26
Exempel
sumdouble 3 ==>
sumfunc double 3 ==>
double 3 + sumfunc double 2 ==>
6 + sumfunc double 2 ==>
6 + (double 2 + sumfunc double 1) ==>
6 + (4 + sumfunc double 1) ==>
6 + (4 + (double 1 + sumfunc 0)) ==>
6 + (4 + (2 + sumfunc 0) ==>
6 + (4 + (2 + 0) ==>
12
27
Tre grundläggande metoder
• Sekvens– Först gör man en sak sedan nästa– ML: funktionskomposition, f (g x) applicera först g på x därefter f
på resultatet
• Val– Alternativa beräkningar beroende på data– ML: if-uttryck, mönstermatchning, (case-uttryck)
• Upprepning– Samma beräkning flera gånger med olika data– ML: rekursion