| Linux – Friheden til at programmere: Version 2.5.20050330 – 2020-12-31 | ||
|---|---|---|
| forrige | Kapitel 2. Vælg et sprog | næste |
ML er et funktionsprogrammeringssprog der har stærkt typetjek med
polymorfi, højereordensfunktioner, funktionsdefinition ved mønstergenkendelse, håndterbare undtagelser (eng. exceptions), strikt evaluering og et avanceret modulsystem. Det betyder at rigtig mange programmeringsfejl bliver opdaget allerede når man oversætter et program, ikke først når man kører det. ML blev oprindelig (ca. 1974) udviklet som metasprog (meta-language) til logiske bevissystemer, men sproget viste sig at være særdeles velegnet til en lang række andre formål.
I dag (2001) findes der to væsentlige varianter af sproget ML:
Standard ML (SML) og Objective Caml (OCaml). Der findes ganske omfattende biblioteker af nyttige funktioner til såvel Standard ML (se[http://www.dina.kvl.dk/~sestoft/sml/sml-std-basis.html|SML Basis Library]) som OCaml. Desuden har de enkelte implementationer deres egne udvidelser til f.eks. databaseadgang, generering af HTML-kode, PNG-billeder, osv.
ML er især udbredt på universiteter og forskningsinstitutioner, og
benyttes i mindre grad i industriel sammenhæng. I Danmark undervises der i Standard ML ved blandt andet Danmarks Tekniske Universitet, Københavns Universitet (DIKU), Aarhus Universitet, Aalborg Universitet og IT-højskolen i København.
Der findes flere implementationer af SML. Både SML of New Jersey og
MoscowML giver mulighed for at lege med SML ved en 'læs-beregn-udskriv løkke' hvor man interagerer direkte med fortolkeren. Man skriver sine udtryk ind, fortolkerne beregner dem og skriver svaret ud. En session med SML kunne derfor se således ud:
Standard ML of New Jersey v110.42 [FLINT v1.5], October 16, 2002-val prim = [18,43,23,10,88];val prim = [18,43,23,10,88] : int list-fun sum [] = 0=| sum (x::xs) = x + sum xs;val sum = fn : int list -> int-val res = sum prim;val res = 182 : int-
Det følgende eksempel forsøger vise en række af de ting der er
specielle for SML og andre funktionsorienterede sprog. SML udleder selv typer for funktioner, og de udledte typer er her indsat over funktionsdefinitionerne i kommentarer(* ... *).
Først defineres en funktionmap:
(* Type: ('a -> 'b) -> 'a list -> 'b list *)
fun map f nil = nil
| map f (x::xs) = f(x) :: map f xs;
Typen fortæller at funktionenmapsom argumenter
tager en anden funktion der tager et argument af typen'aog returnerer en værdi af typen'b. Det andet argument tilmaper en liste hvor elementerne har typen'aog så returnerer map en liste af elementer af typen'b. Men hvad er'aog'b?
'aer en typevariabel. Hvis man kaldermapmed en funktion der tager et heltal som
argument vil'ablive bundet til typenint. Dette kaldes typepolymorfi.maparbejder bare på lister og er ligeglad med hvad funktionenfgør ved elementerne.
Funktionen er defineret med mønstergenkendelse. Det vil sige at der
er listet en række tilfælde af definitionen op hvor SML så vil vælge den første der passer.nilog(x::xs)er mønstre som SML sammenligner med hvad funktionen bliver kaldt med.niler den tomme liste og(x::xs)er en liste hvor det første element bliver bundet til variablenxog resten af listen bliver bundet til variablenxs.
::er en infix-operator der laver
listesammensætning.maptager altså en funktion og en liste og udføre funktionen på alle elementerne i listen. Damaptager en anden funktion som argument kaldes den en højereordensfunktion.
Følgende enkle funktion tager et heltal og ganger det med 2:
(* Type: int -> int *) fun double n = 2 * n;
Ikke noget specielt her.
Nu vil vi så anvende ovenstående to funktioner til at lave en
funktion der tager en liste af heltal og fordobler dem:<code>(* Type: int list -> int list *)
val doublelist = map double;</code>
Bemærk at vi her brugervalog ikkefun. Det er fordi vi egentligt ikke laver en ny
funktion men tildeler navnetdoublelisten værdi (funktioner er nemlig lige så meget værdier som heltal er).
Det næste man bemærker er atmapkaldes med kun
et argument. Menmaphavde da to argumenter? Dette kaldes 'currying'. Vi kaldermapmed det første argument, det returnerer en funktion der tager resten af argumenterne.
Vi kunne også have undladt at definere funktionendoubleog bruge en anonym funktion:
(* Type: int list -> int list *) val doublelist = map (fn x => 2 * x);
Den slags anonyme funktioner bruges ganske ofte i SML.
SML indeholder ikke de løkkestrukturer man normalt bruger. Skal man beregne noget iterativt bliver man
derfor nødt til selv at lave nogle funktioner der klarer det for
sig. Man kunne for eksempel bruge følgende funktion:<code>(* Type: ('a -> 'a) -> int -> 'a -> 'a *)
fun iterate f 0 x = x
| iterate f i x = iterate f (i-1) (f x);</code>
iteratetager en funktionfog udfører den et antal gange på værdienx.