onsdag 7. desember 2011 Julekalender Polyglot Haskell
Haskell er en tungvekter. Haskell er vakkert, elegant og matematisk, og samtidig anvendelig i den virkelige verden. Haskell kan gjøre deg mer produktiv, og kan resultere i kode som er mer fleksibel og derfor bedre egnet for et langt liv med mange endringer. Og Haskell's kompilator og sterke typing tillater ikke noe tull, men hjelper deg til å skrive feilfri kode.
Ingressen inneholder noen sterke påstander. Jeg har ikke nok erfaring til å garantere at de er riktige, men de som bruker Haskell skryter i alle fall noe voldsomt av språket sitt. De sier at det er gøy å lære og å jobbe med Haskell. At det vil utvide hjernen din, og raskt gjøre deg til en bedre programmerer også i andre språk. Dette høres ut som gode grunner til å ta en titt.
De stolte Haskellanerne sier også at språket egner seg bra til å løse real-world problems, men at det kan ta mange måneder med studie før man når et nivå hvor det blir realistisk.
For Haskell er vanskelig! Enhver kompetent programmerer kan lære det, men det kan kreve mer tid og motivasjon enn man tror. For de fleste av oss innebærer Haskell at vi må lære en ny måte å tenke på – det er ikke bare snakk om en ny syntaks for gamle konsepter og teknikker. Til å begynne med kan dette være frustrerende, og enkle oppgaver kan virke nesten umulige å løse.
Personer uten tidligere programmeringserfaring vil faktisk kunne lære det raskere, fordi det er færre ting man må "glemme".
Haskell er resultatet av et forsøk på å samle det beste fra diverse funksjonelle programmeringsspråk. Det er en åpen standard definert av en komité, og første versjon kom i 1990. Den gjeldende versjonen er Haskell 2010.
Haskell er altså et funksjonelt språk, et rent funskjonelt språk for å være presis. Men det er også imperativt, for rent betyr ikke nødvendigvis det du tror. Haskell er veldig fleksibelt, og kan også støtte ting som objektorientering, aspekter og logisk programmering.
Haskell er lazy (for de som vet hva det er), har pattern matching og list comprehensions, og et sterkt, statisk typesystem. Jeg kunne sagt mye mer, men uansett hva jeg sier vil noen komme og si at jeg har missforstått Haskell helt, så nå er det...
Igjen har jeg implementert en løsning for Euler problem 1 – hvordan finne summen av alle tall mindre enn 1000 som er delelige på 3 eller 5. Jeg har delt programmet opp i mindre biter for at det skal bli lettere å fordøye. Her er første "chunk", som definerer modulen Main, importerer funksjonen range som jeg trenger senere, og definerer min første funksjon:
10 module Main where 11 12 import Ix (range) 13 14 zero :: Integer -> Bool 15 zero x = x == 0
Den første funksjonen heter zero. Linje nummer 14 er en typedeklarasjon, og er ikke påkrevd. Den sier rett og slett at zero er en funksjon som tar inn en Integer og returnerer en Bool. Selve implementasjonen følger på linje 15; den sier at resultatet av zero x, hvor x altså er en Integer, er det samme som x == 0, altså True hvis x er 0, og False hvis x er noe annet enn 0.
Neste funksjon kan brukes til å sjekke om et tall er delelig på 3 eller 5:
17 multipleOf3or5 :: Integer -> Bool 18 multipleOf3or5 x = 19 let modX = mod x 20 multipleOf = zero . modX 21 in multipleOf 3 || multipleOf 5
multipleOf3or5 illustrerer flere Haskell-features. Let lar meg definere et par verdier som jeg kan bruke videre i funksjonen. Definisjonen av modX er et eksempel på partial application – mod er nemlig en funksjon som tar to parametre, men jeg har bare "sendt inn" ett. Jeg har dermed fått laget meg en ny funksjon (altså modX) som tar én parameter.
Jeg har snakket om denne teknikken et par ganger tidligere, i posten komponere funksjoner i F# og i curry-oppskrifter for sultne utviklere.
For å lage multipleOf-funksjonen i linje 20 bruker jeg Haskell's dot-operator (.), som komponerer en ny funksjon fra to andre. Å si multipleOf = zero . modX er det samme som å si multipleOf x = zero (modX x). Altså er multipleOf nå en funksjon som først sender sine argumenter til modX-funksjonen, og så tar resultatet av dette og sender inn til zero-funksjonen.
Det bør nå være mulig å forstå hvordan multipleOf3or5 virker. Videre har jeg laget en høyereordens-funksjon som filtrerer en liste med tall og til slutt summerer de filtrerte tallene:
23 sumWhere :: (Integer -> Bool) -> [Integer] -> Integer 24 sumWhere f lst = sum $ filter f lst
Først har vi typedeklerasjonen av sumWhere som basically sier at funksjonen først har en parameter som er en funksjon som tar inn en Integer og returnerer en Bool (som f.eks. multipleOf3or5). Deretter har den et parameter som er en liste av Integer. sumWhere skal til slutt returnere en Integer.
Selve implementasjonen bruker et dollartegn for å unngå å måtte bruke paranteser (Haskell har lært fra Lisp at utviklere flest ikke skjønner denslags). Men sum $ filter f lst kunne i stedet ha blitt skrevet som sum (filter f lst). Listen filtreres altså på funksjonen f, og resultatet av dette sendes til funksjonen sum.
Og da gjenstår det bare å koke det jeg har laget sammen for å beregne løsningen på oppgave:
26 euler1 :: Integer 27 euler1 = sumWhere multipleOf3or5 $ range (1,999)
euler1 er – alt etter hvordan du ser det antar jeg – en Integer eller en funksjon som evaluerer til / returnerer en Integer. Jeg tar en range fra 1 til 999, og bruker sumWhere til å filtrere og summere listen vha. multipleOf3or5.
Denne kodesnutten har så vidt skrapet i overflaten på hva Haskell er, men forhåpentligvis gir det et lite inntrykk av hva du vil møte.
Den mest kjente implementasjonen av Haskell heter The Glasgow Haskell Compiler (GHC), og funker på Windows, Linux, Mac og mange andre steder. Den er ekstremt rask, har god støtte for concurrency og paralell programmering, og inkluderer blant annet støtte for Software Transactional Memory (STM). GHC laster du ned herfra.
De to mest populære ressursene for å lære språket er bøkene Learn You a Haskell og Real World Haskell. Begge er gratis tilgjengelig online, men du kan også kjøpe dem i dødt tre om du foretrekker det.
Ellers er haskell.org stedet du ønsker å starte for å utforske språket. Det kan være litt tøft i starten, men hold ut – det er verdt det. Lykke til!