1 Introduktion til Elm
I dette kapitel skal vi i gang med at lære Elm. Elm er et programmeringssprog, som gør det muligt for os at gøre vores hjemmeside dynamisk. Vi kan altså begynde at bygge interaktive knapper, loginsystemer, spil og stort set alt andet, som du ser, når du surfer rundt på nettet. Man kan bruge mange forskellige sprog til at gøre en hjemmeside dynamisk. Vi har valgt Elm, fordi det er et funktionelt programmeringssprog. Som ordet lægger op til, kan vi altså overføre meget af vores forståelse fra mængder og funktioner i matematik til begreber i Elm.
Inden vi begynder at bygge hjemmesider med Elm, skal vi se på nogle af de grundlæggende ting man kan med Elm. Og du skal selvfølgelig kode med!
For at komme i gang skal vi lige en tur forbi terminalen for at starte elm repl. Det går du sådan her:
-
Åbn terminalen.
- På Windows søger du efter "Kommandoprompt" i søgefeltet og trykker Enter.
- På Mac søger du efter "Terminal" i en Spotlight-søgning og trykker på Enter.
-
I terminalen skriver du
elm repl. Du skulle gerne få en besked i terminalen, der ser nogenlunde sådan her ud:---- Elm 0.19.1 ---------------------------------------------------------------- Say :help for help and :exit to exit! More at https://elm-lang.org/0.19.1/repl -------------------------------------------------------------------------------- -
Når man er færdig med at skrive i
elm repl, kan man afslutteelm repligen ved at trykke Ctrl+D eller Cmd+D. Så er man tilbage i den normale terminal igen.
1.1 Typer
En type i Elm er pendant til mængder i matematik: Man kan altså tænke på en type som en samling af objekter. Vi kalder objekterne for værdier af typen.
Ligesom med mængder i matematik, kan man selv definere sine egne typer, men der også nogle typer, der er så almindelige, at de allerede er bygget ind i Elm. Akkurart, som der allerede findes symboler for heltallene (Z) elller de reelle tal (R) i matematik. Lad os se på et par eksempler:
- Typen
Inthar alle heltal som værdier. Vi siger for eksempel: "2har typenInt". Og det er helt analogt til at sige: "2 er et helttal" eller "2 er et element i Z".Intstår for "integer", som betyder heltal på engelsk. - Typen
Floathar alle decimaltal som værdier, for eksemepel: 3.1 og -9.4.Floatstår for floating-point numbers, og du kan tænke på den som en pendant til de reelle tal R.
Læg mærke til, at vi navngiver typer med stort begyndelsesbogstav, ligesom mængder i matematik bliver angivet med store bogstaver.
Lad os prøve ovenstående af i elm repl. Som altid er det en rigtig god ide at kode med selv!
Prøv at skrive
3.14159 i elm repl og tryk derefter på Enter. Nu fortæller elm repl dig, hvilken type 3.14159 er:
> 3.14159
3.14159 : Float
Hvad sker der, hvis vi skriver 2 og trykker på Enter? Vi forventer, at elm repl vil fortælle os, at 2 er af typen Int. Men det sker faktisk ikke! I stedet får vi denne besked:
> 2
2 : number
Der er faktisk to ting, der er overraskende her:
elm replsiger, at 2 er etnumber, ognumberer skrevet med lille begyndelsesbogstav.
Typer har altid stort begyndelsesbogstav, så number er ikke en type! Men hvad er det så? Formelt set er number en type class, men det er ikke relevant for os lige nu. Det der er vigtigt for os er, at Elm skriver at 2 er et number, fordi Elm ikke ved, om vi har tænkt os 2 skal bruges som et helttal eller et decimaltal. Vi bliver altså opmærksom gjort på, at 2 kan være enten af typen Int eller af typen Float, når vi bare skriver 2.
Det oplagte spørgsmål fra et matematisk synspunkt er nu: "Jamen er alle værdier af typen Int ikke også værdier af typen Float?" Med andre ord, er Int ikke bare en "deltype" af Float, ligesom Z er en delmængde af R?
Svaret er: NEJ! Her adskiller typer sig fra mængder: En værdi kan kun have én type i en given kontekst. Så tallet 2 kan enten have typen Int eller typen Float, men det kan ikke have begge typer på samme tid! Det lyder nok lidt underligt for en matematiker, men nu introducerer vi funktioner, og derefter kan vi præcist forstå, hvad der menes.
1.2 Min første funktion i Elm
Når vi skal definere en funktion i Elm foregår det på stort set samme måde, som det gør i matematik. Lad os for eksempel prøve at definere en funktion, der tager et heltal som input og giver et dobbelt så stort heltal som output. Det ville se sådan her ud i matematik:
Matematik
f : ℤ ⟶ ℤ f(x) = x + x
Lad os, for en god ordens skyld, forklare ovenstående:
- Først angives funktionens navn, "f".
- Dernæst specificeres domæne og kodomæne, eller inputmængde og outputmængde om man vil.
- Til sidst angives funktionens forskrift: f(x) = x + x.
Vi kan lave denne funktion i elm repl således:
Elm
f : Int -> Int f x = x + x
Det ligner jo den matematiske definition rigtig meget, men lad os igen løbe det hele igennem:
- Først angives funktionens navn, "f".
- Dernæst specificeres input typen og output typen.
- Til sidst angives funktionens forskrift: f x = x + x.
Læg mærke til, at vi undelader de to parenteser omkring x. Det gør vi altid i Elm!
Implementer funktionen ovenfor i elm repl. Det gør du ved at skrive:
ElmPrøv derefter at kalde funktionen med værdien
f : Int -> Int f x = x + x
2. Det gør du ved at skrive:
f 2og trykke på Enter. Sker der det, du forventede?
Prøv nu kalde funktionen med værdien 2.0, det gør du ved at skrive:
f 2.0Der går noget galt. Kan du forklare, hvad der går galt? (Hint: læs det
elm repl skriver.)
I øvenstående eksempel går det godt, når vi skriver f 2, fordi vi har fortalt Elm, at f skal have et input af typen Int. Elm ved derfor at 2 i denne kontekst må have typen Int og ikke typen Float.
Derimod går det galt, når vi skriver f 2.0, fordi Elm forventer at f skal have en input værdi af typen Int, men i stedet giver vi den 2.0, som har typen Float. Det vil Elm ikke være med til, og så får vi en fejl! Lige nu virker det måske dumt og ufleksibelt, men når koden bliver lang og kompleks er det en stor fordel, fordi det hjælper os med at holde overblik over hvad, der kommer ind og ud af de forskellige funktioner.
1.3 God stil i Elm
Når vi først kommer igang, kommer vi til at skrive rigtig mange funktioner, og det kan blive svært at kende forskel på dem. Derfor navngiver vi ikke funktioner i Elm med f, g og h som i matematik. I stedet giver vi dem navne, som forklarer, hvad de skal bruges til.
Funktionen vi ovenfor kaldte f, burde vi i stedet definere således:
Elm
doubleInteger : Int -> Int
doubleInteger x =
x + x
Vi har altså navngivet funktionen doubleInteger i stedet for f, så det er lettere at huske hvad funktionen gør. Læg desuden mærke til, at vi navngiver funktionen med lille begyndelsesbogstav. Det gør vi altid i Elm:
- Typer navngives med store bogstaver,
- mens funktioner navngives med små bogstaver.
Læg også mærke til at vi har skiftet linje efter = og indrykket næste linje med Tab. Det gør vi, fordi vores funktionsforskrifter kan blive meget lange, og så er det lettere at læse, hvis de er indrykket på de efterfølgende linjer.
Definer en funktion
squareInteger, som tager en værdi af typen Int og returnerer en værdi af typen Int.
squareInteger : Int -> Int
Funktionen skal multiplicere inputtet med sig selv, så vi for eksempel får følgende output:
Elm
> squareInteger 7
49 : Int
1.4 Typen String
Vi er bestemt ikke begrænset til at arbejde med tal i Elm. Vi kan blandt andet også arbejde med tekst. Tekst har typen String, og vi angiver, at en værdi har typen String ved at bruge anførselstegn.
Elm
> "Hello World"
"Hello World" : String
elm repl fortæller os, at "Hello World" er af typen String. Som du måske allerede har gættet, så kan enhver sekvens af karakterer være en String.
Vi kan arbejde med og udføre operationer på værdier af typen String, ligesom vi kan med værdier af typerne Int og Float. For eksempel kan vi sammensætte tekststrenge:
Elm
> "Hej " ++ "Peter"
"Hej Peter" : String
Definer en funktion
hejMedDig : String -> String
som tager et navn som input og giver følgende output:
Elm
> hejMedDig "Peter"
"Hej med dig, Peter" : String