1 Mönstermatchning och rekursion Nr 4
2 Förenklad notation val fnname = fn name => expression Förenklas till fun fnname name = expression Exempel fun 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 fun taxdue sum = fn tax => sum * tax div 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 expression 1 then expression 2 else expression 3 –expression 1 måste returnera ett boolesk värde –expression 2 och expression 3 måste returnera värden av samma typ Om expression 1 evalueras till true är värdet av hela uttrycket värdet av expression 2. Om expression 1 evalueras till false är värdet av hela uttrycket värdet av expression 3.
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 pattern 1 => expression 1 | pattern 2 => expression 2: | pattern N => expression N Till att börja med kan ett mönster (pattern i ) 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 pattern 1 => fkn_body 1 | pattern 2 => fkn_body 2 :: | pattern N => fkn_body N Motsvarar fun name pattern 1 = fkn_body 1 | name pattern 2 = fkn_body 2 ::: | name pattern N = fkn_body N
11 Exempel fun not x =if x (* = true *) then false else true; val not = fn : bool -> bool fun not true = false | not false = true val 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 undantag exception name Använda undantag raise name
15 Exempel exception Illegal_light fun 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 => true val 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 ( …) 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 n fun power x 0 = 1 | power x n = x * power x (n-1) val power = fn : int -> int -> int val power2 = power 2 val power2 = fn : int -> int
23 Generaliserad summa Summan av kvadraten av alla tal mellan 0 och n fun 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 n fun double n = 2 * n fun 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 parameter fun sumfunc f 0 = 0 | sumfunc f n = f n + sumfunc f (n-1)
25 Specialisera Specialisera för att få de tidigare funktionerna fun id x = x val sum = sumfunc id val sumsq = sumfunc sq val 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