1 Kap.4 Funksjoner Tre viktig ting ifm. funksjoner: navn parameter (input) oppskrift (body) for å beregne resultat (output) Syntaks: <name> <parameter> = <body> Deklarerte funksjoner kan brukes i uttrykk (prefiks, høyest presedens)
2 Eksempler successor n = n+1 successor (n) = n+1 abs(n) = if n >= 0 then n else -n len l = if null l then 0 else 1 + len tail l (* feil *) len l = if null l then 0 else 1 + len (tail l) fib n = if n == 0 n == 1 then 1 else fib (n-1) + fib (n-2)
3 Evaluering av uttrykk Gitt en funksjon <name> <parameter> = <body> Innerst (innermost) evaluering av <navn>(<actual-par>) evaluer (<actual-par>) til en verdi sett inn verdien for <parameter> i <body> evaluer det resulterende uttrykket <valued-body> Ytterst (outermost) evaluering av <navn>(<actual-par>) sett inn uttrykket <actual-par> for <parameter> i <body> evaluer det resulterende uttrykket <actual-body>
4 Eksempler på evaluering Gitt en funksjon successor n = n+1 Innerst (innermost) evaluering av successor (3+2) evaluer 3+2 til 5 sett inn 5 for n i n+1 evaluer det resulterende uttrykket 5+1 Ytterst (outermost) evaluering av successor(3+2) sett inn uttrykket 3+2 for n i n+1 evaluer det resulterende uttrykket (3+2)+1
5 Fordeler og ulemper Innermost = call-by-value enkelt og naturlig kan evaluere unødvendig: fst(1,1 div 0) Outermost = lazy evaluation finner alltid en verdi hvis det eksisterer en kan gjøre dobbelt arbeid: double x = x + x double (2*3) Haskell bruker lazy evaluation
6 McCarthy s 91-funksjon Eksempel på rekursjon, se her Definisjon: f x = if x > 100 then x-10 else f (f (x+11) ) Vanskelig å forstå operasjonelt Lettere å forstå deklarativt: x > 100 f(x) = x 10, spesielt f101 = 91 90 x 100 x + 11 > 100 f(x) = f(x + 11 10) = f(x + 1) =... = f101 = 91 79 x 89 90 x + 11 100, faktisk fx = 91 for alle x 100 Innermost og outermost evaluering på tavla
Konfluens I alle rene funksjonelle språk (pure FP) gjelder det at enhver evalueringsstrategi som finner en verdi til et gitt uttrykk, finner samme verdi. Det er ikke mulig at to evalueringer av samme uttrykk finner forskjellige verdier. Det som er mulig er at en strategi finner en verdi mens en annen strategi ikke finner noen verdi. 7
8 Rekkevidde For å kunne evaluere et uttrykk må hver variabel være bundet Å binde en variabel skjer f.eks. ved bruk av let Rekkevidde (scope) til en bundet variabel er deluttrykket hvor bindingen gjelder Eksempler let x=3 in <u>, scope til x er <u> let x=3 in let y=2 in x+y : scope til x er rød, scope til y er x+y let x=3 in let y=x in <u> : scope til x er rød, scope til y er <u> let x=3 in y+1: feil?
9 Rekkevidde (forts.) successor n = n+1, rød scope til n successor x = x+1, rød scope til x Bundete variabler: navn urelevant (men...) Obs: også successor er en bundet variabel (blå scope) let successor n = n+1 in successor 4 let etterfoelger x = x+1 in etterfoelger 4
10 Flere eksempler Rekursjon : let even n = n==0 even (n-2) in even 4 Samtidig rekursjon: let even x = if x==0 then True else if x==1 then False in else odd (x-1) odd x = if x==0 then False else if x==1 then True (even 24,odd 24) else even (x-1)
11 Typer Type-sjekking og type-avledning behandles dypere om noen uker Her legger vi bare frem noen type-fenomener Haskell klarer ofte å avlede en type til et uttrykk, med mindre 1. uttrykket er galt (oftest), eller 2. uttrykket er OK men meget komplisert (sjeldent) I det sjeldne tilfelle 2 skal man legge til noen type-informasjon
12 Strukturelle regler Hvis <u> :: Int og <v> :: Int, så <u> + <v> :: Int Hvis <u> :: <t l> og <v> :: <t r>, så (<u>,<v>) :: (<t l>,<t r>) Hvis <u> :: <t i> -> <t o> og <v> :: <t i>, så <u> <v> :: <t o> Disse tre henger sammen: (+) :: (Num a) => a -> a -> a Flere andre regler brukes til type-avledning
13 Type-ekvivalens Type-ekvivalens er likhet for typer, dvs. at hvis <u> :: <type> og <type> og <type > er ekvivalente, så <u> :: <type > Etter type Intpair = (Int,Int) er Intpair og (Int,Int) ekvivalente Så er også, f.eks., Intpair -> Bool og (Int,Int) -> Bool ekvivalente
14 Type-ekvivalens Formell definisjon: T og <type> er ekvivalente hvis type T = <type> Type-ekvivalens er refleksiv, symmetrisk og transitiv Hvis <type1> og <type2> er ekvivalente, så er [<type1>] og [<type2>] Hvis <t1> og <t2> er ekvivalente og <t 1> og <t 2> er ekvivalente, så er (<t1>,<t 1>) og (<t2>,<t 2>) ekvivalente og <t1>-><t 1> og <t2>-><t 2> ekvivalente
15 Mer om typer i Haskell Haskell tillater operator overloading: 1 + 2, 3.14 + 1.0 Haskell bruker type-klasser for tall: 2 * 3.14 :: (Fractional t) => t Haskell støtter polymorfi: len :: [a] -> Int len [] = 0 len (_:tl) = 1 + len tl (len [1,2]) + (len ["tre"])