1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
|
---
language: Haskell
filename: learnhaskell-sv.hs
contributors:
- ["Adit Bhargava", "http://adit.io"]
translators:
- ["Edward Tjörnhammar", "http://edwtjo.me"]
lang: sv-se
---
Haskell skapades för att vara ett praktiskt, rent, funktionellt
programmeringsspråk. Det är känt för sin använding av monader och dess
härledande typsystem men anledningen till att jag ständigt återbesöker språket
är på grund av dess elegans. Haskell gör programmering till ett rent nöje.
```haskell
-- Radkommenterar börjar med två bindestreck.
{- Flerradskommentarer innesluts av vänster/höger måsvinge bindestreck
block på detta vis.
-}
----------------------------------------------------
-- 1. Fördefinierade datatyper och operatorer
----------------------------------------------------
-- Du har siffror
3 -- 3
-- Matte fungerar som förväntat
1 + 1 -- 2
8 - 1 -- 7
10 * 2 -- 20
35 / 5 -- 7.0
-- Division är normalt inte heltalsdivision
35 / 4 -- 8.75
-- Heltalsdivision, här infix div
35 `div` 4 -- 8
-- Boolar (Sant och Falskt) är fördefinierade
True
False
-- Samt dess operationer
not True -- False
not False -- True
1 == 1 -- True
1 /= 1 -- False
1 < 10 -- True
-- I ovanstående exempel är `not` en funktion vilken bara tar ett argument.
-- Haskell behöver inte paranteser för sina funktionsanrop... alla argument
-- ges mellanslagsseparerade direkt efter funktionen. Det övergripande mönstret
-- är:
-- func arg1 arg2 arg3...
-- Se sektionen om funktioner för information om hur du skriver dina egna.
-- Strängar och bokstäver
"Detta är en sträng"
'a' -- bokstav
'Du kan inte använda enkelfnutt för strängar.' -- fel!
-- Strängar kan konkateneras
"Hej " ++ "världen!" -- "Hej världen!"
-- En sträng är en lista av bokstäver
['H', 'e', 'j', 's', 'a', 'n'] -- "Hejsan"
"Detta är en sträng" !! 0 -- 'D'
----------------------------------------------------
-- 2. Listor och Tupler
----------------------------------------------------
-- Varje element i en lista måste ha samma typ.
-- Dessa listor är ekvivalenta:
[1, 2, 3, 4, 5]
[1..5]
-- Intervall är mångsidiga.
['A'..'F'] -- "ABCDEF"
-- Man kan stega intervall.
[0,2..10] -- [0, 2, 4, 6, 8, 10]
[5..1] -- [] (Haskell förutsätter normalt inkrement)
[5,4..1] -- [5, 4, 3, 2, 1]
-- Indexering in i en lista
[1..10] !! 3 -- 4 (nollindexerat)
-- Man kan ha oändliga listor i Haskell!
[1..] -- listan över alla naturliga tal
-- Oändliga listor fungerar enbart för att Haskell har "lat evaluering".
-- Det betyder att Haskell bara evaluerar de uttryck den måste. Du kan alltså
-- fråga efter det 1000:e elementet i en oändlig lista och Haskell kommer då ge
-- dig det:
[1..] !! 999 -- 1000
-- Nu har Haskell evaluerat element 1 till 1000 i denna lista... men resten
-- av medlemmarna i denna oändliga lista existerar inte ännu! Haskell kommer
-- faktiskt inte utvärdera element den inte måste.
-- Sammanslagning av två listor
[1..5] ++ [6..10]
-- Lägg till 0 vid listhuvudet
0:[1..5] -- [0, 1, 2, 3, 4, 5]
-- fler listoperationer som huvud, svans, initiella samt sista
head [1..5] -- 1
tail [1..5] -- [2, 3, 4, 5]
init [1..5] -- [1, 2, 3, 4]
last [1..5] -- 5
-- listomfattningar
[x*2 | x <- [1..5]] -- [2, 4, 6, 8, 10]
-- med bivilkor
[x*2 | x <- [1..5], x*2 > 4] -- [6, 8, 10]
-- Varje element i en tupel kan ha olika typ men en tupel kan bara ha en
-- fixerad, eller statisk, längd.
-- En tupel:
("haskell", 1)
-- För att komma åt element i ett par, alltså en 2-tupel, finns
-- de fördefinierade funktionerna:
fst ("haskell", 1) -- "haskell"
snd ("haskell", 1) -- 1
----------------------------------------------------
-- 3. Funktioner
----------------------------------------------------
-- En enkel funktion med två parametrar
add a b = a + b
-- Notera även att om du använder ghci (Haskellinterpretatorn) kommer du behöva
-- använda `let` namnbindning för att synliggöra din funktionsdeklaration,
-- alltså
let add a b = a + b
-- För att använda funktionen
add 1 2 -- 3
-- Man kan även göra funktionsanropet infix, alltså mellan parametersättningen,
-- med hjälp av bakåtfnuttar:
1 `add` 2 -- 3
-- Du kan även definiera funktioner vars funktionsnamn avsaknar bokstäver!
-- Med hjälp av parenteser kan du därmed definiera operatorer (normalt infix)!
-- Följande är en operator för heltalsdivision, vilken förlitar sig på div:
(//) a b = a `div` b
35 // 4 -- 8
-- Funktionsvakter: ett enkelt sätt att grena ut dina funktioner
fib x
| x < 2 = 1
| otherwise = fib (x - 1) + fib (x - 2)
-- Mönstermatchning fungerar på liknande vis. Här ger vi tre olika
-- parametermatchningar för vårat fib-resulat. Haskell kommer automatiskt följa
-- första bästa träff, uppifrån ned, vars vänstra sida om likhetstecknet matchar
-- anroparens parametervärde.
fib 1 = 1
fib 2 = 2
fib x = fib (x - 1) + fib (x - 2)
-- Mönstermatchning på tupler:
foo (x, y) = (x + 1, y + 2)
-- Mönstermatchning på listor. Här är `x` det första elementet i listan och `xs`
-- är resten av listan. Nu kan vi skriva våran egen map-funktion
minMap func [] = []
minMap func (x:xs) = func x:(minMap func xs)
-- Anonyma funktioner, eller lambdauttryck, skapas med hjälp av omvänt
-- snedstreck, följt av parametrarna
minMap (\x -> x + 2) [1..5] -- [3, 4, 5, 6, 7]
-- Användning av fold (även kallad `inject`, `reduce`, osv.) tillsammans med en
-- anonym funktion. `fold1` är en vänstervikande funktion och använder första
-- värdet i listan som det initiella värdet för ackumulatorn.
foldl1 (\acc x -> acc + x) [1..5] -- 15
----------------------------------------------------
-- 4. Mer funktioner
----------------------------------------------------
-- Partiell applikation:
-- Om du inte anropar funktionen med alla sina argument
-- blir den partiellt applicerad. Det betyder att du erhåller en funktion där en
-- delmängd av parametrarna blivit värdesatta men några är fortfarande fria.
add a b = a + b
foo = add 10 -- foo är nu en funktion som tar ett nummer och lägger till 10 till
-- det
foo 5 -- 15
-- Ett annat sätt att skriva samma sak
foo = (10+)
foo 5 -- 15
-- Funktionskomposition:
-- Operatorn `.` kedjar ihop funktioner
-- Till exempel, nedan är `foo` en funktion som tar ett värde, den adderar 10
-- till det, multiplicerar det resultatet med 4 och sen ersätts med det värdet.
foo = (4*) . (10+)
-- 4*(10+5) = 60
foo 5 -- 60
-- Precedensordning:
-- Haskell har en operator `$`. Denna operator applicerar en funktion till en
-- given parameter med dess precedens. I kontrast mot vanlig
-- funktionsapplikation, vilket har den högsta utvärderingsprioriteten 10 och
-- associerar till vänster, har denna prioritetsordning 0 och är
-- högerassociativ. Denna låga prioritet medför att parameteruttrycket till
-- höger om operatorn får det reducerat innan det appliceras till sin vänster.
-- före
even (fib 7) -- falskt
-- ekvivalent
even $ fib 7 -- falskt
-- med funktionskomposition
even . fib $ 7 -- falskt
----------------------------------------------------
-- 5. Typsignaturer
----------------------------------------------------
-- Haskell har ett väldigt starkt typsystem, alla giltiga uttryck har en typ.
-- Några grundläggande typer:
5 :: Integer
"hello" :: String
True :: Bool
-- Funktioner har också typer,
-- `not` tar en bool och returnerar en bool:
-- not :: Bool -> Bool
-- Här är ett exempel på en funktionssignatur vilken beskriver en funktion som
-- reducerar två heltal till ett:
-- add :: Integer -> Integer -> Integer
-- Trots att Haskell härleder typen på icke typsatta uttryck är det bra form att
-- explicit ange dessa för ens deklarerade funktioner:
double :: Integer -> Integer
double x = x * 2
----------------------------------------------------
-- 6. Kontrollflöde och Ifsatser
----------------------------------------------------
-- if-sats
haskell = if 1 == 1 then "awesome" else "awful" -- haskell = "awesome"
-- if-statser kan spridas över rader men indentering har betydelse
haskell = if 1 == 1
then "awesome"
else "awful"
-- case uttryck: följande är ett exempel på kommandoradsparsning
case args of
"help" -> printHelp
"start" -> startProgram
_ -> putStrLn "bad args"
-- Haskell har inte loopar istället används recursion.
-- map applicerar en funktion över varje element i en lista
map (*2) [1..5] -- [2, 4, 6, 8, 10]
-- man kan deklarera en for funktion genom att använda map
for array func = map func array
-- och därefter använda den tillsammans med en anonym funktion för att
-- efterlikna en loop
for [0..5] $ \i -> show i
-- men vi kunde även ha skrivit på följande vis:
for [0..5] show
-- Du kan använda foldl eller foldr för att reducera en lista
-- foldl <fn> <initial value> <list>
foldl (\x y -> 2*x + y) 4 [1,2,3] -- 43
-- Vilket är samma sak som
(2 * (2 * (2 * 4 + 1) + 2) + 3)
-- foldl viker från vänster, foldr från höger
foldr (\x y -> 2*x + y) 4 [1,2,3] -- 16
-- Vilket alltså är samma sak som
(2 * 1 + (2 * 2 + (2 * 3 + 4)))
----------------------------------------------------
-- 7. Datatyper
----------------------------------------------------
-- Såhär definierar du din egen datatyp i Haskell
data Color = Red | Blue | Green
-- När du gjort det kan du använda den i funktionssignaturer och uttryck
say :: Color -> String
say Red = "Du är Rö!"
say Blue = "Du är Blå!"
say Green = "Du är Grön!"
-- Dina datatyper kan även ta parametrar
data Maybe a = Nothing | Just a
-- Följande uttryck är alla specialiseringar av typen Maybe
Just "hello" -- har typen `Maybe String`
Just 1 -- har typen `Maybe Int`
Nothing -- har typen `Maybe a` för alla `a`
----------------------------------------------------
-- 8. Haskell IO
----------------------------------------------------
-- Även om IO inte kan förstås fullt ut utan att först förklara monader är det
-- inte svårt att lära sig tillräckligt för att komma igång
-- När ett Haskellprogram körs är det topnivåns main som körs. Main måste
-- returnerna ett värde av typen `IO a`, för någon typ `a`. Till exempel:
main :: IO ()
main = putStrLn $ "Hej, himmelen! " ++ (say Blue)
-- putStrLn har typen type String -> IO ()
-- Det är enkelt att göra IO om du kan implementera ditt program som en funktion
-- från String till String. Funktionen
-- interact :: (String -> String) -> IO ()
-- tar denna funktion och matar den med strängdata från stdin och skriver ut
-- resultatet som en sträng på stdout
countLines :: String -> String
countLines = show . length . lines
main' = interact countLines
-- Du kan tänka på värden av typen `IO ()` som att representera
-- händelsesekvenser du vill att din dator skall utföra, likt imperativa språk.
-- För att kedja ihop händelsesekvenser använder man ett syntaktiskt socker
-- kallat do-notation. Som exempel:
sägHej :: IO ()
sägHej = do
putStrLn "Vad heter du?"
namn <- getLine -- denna raden läser en rad från stdin och vi binder den till
-- funktionsnamnet `namn`
putStrLn $ "Hejsan, " ++ namn
-- Övning: Skriv din egen version av interageringsfunktionen `interact` som bara
-- läser en rad från stdin, vanliga `interact` läser till EOF.
-- Koden i sägHej kommer dock aldrig exekveras. Den enda handlingen som blir det
-- är som bekant utvärderingen av `main`.
-- För att köra `sägHej` kommentera ut definition av `main` ovan och
-- avkommentera nedanstående version:
-- main = sayHello
-- Låt oss bättre förstå hur funktionen `getLine` vi just använde fungerar. Dess
-- typsignatur är:
-- getLine :: IO String
-- Du kan tänka på typen `IO a` som att representeras av ett datorprogram vilken
-- kommer generera ett värde av typen `a` när det exekveras (utöver allt annat
-- det kan tänkas göra). Vi kan därtill binda detta värde till ett namn för
-- återanvändning genom att använda `<-`. Vi kan även skapa våran egen handling
-- av typen `IO String`:
handling :: IO String
handling = do
putStrLn "Detta är en rad, tihi"
input1 <- getLine
input2 <- getLine
-- Typen av hela `do` blocket är vad som står på sista raden. Här är även
-- `return` inte ett nyckelord i språket utan en funktion med en typsignatur
return (input1 ++ "\n" ++ input2) -- return :: String -> IO String
-- Vi kan använda `return` på samma sätt som vi använde `getLine`:
main'' = do
putStrLn "Jag kommer eka två rader!"
result <- handling
putStrLn result
putStrLn "Tack och hej leverpastej!"
-- Typen `IO` är ett exempel på en monad. Sättet Haskell utnyttjar monader på är
-- anledningen till hur språket kan bibehålla sin renhet. En funktion vilken
-- interagerar med omvärlden (alltså gör IO) blir markerad med `IO` i sin
-- typsignatur. Detta låter oss enkelt upptäcka vilka funktioner som är "rena"
-- (inte interagerar med omvärlden eller är tillståndsoberoende) and vilka
-- funktioner som inte är det.
-- Detta är ett mäktigt särdrag eftersom det är enkelt att köra rena funktioner
-- sammanlöpande; Samtidig programmering är enkel att göra i Haskell.
----------------------------------------------------
-- 9. Haskell REPL (kodtolk)
----------------------------------------------------
-- Efter installation av GHC kan vi starta tolken genom att skriva `ghci`.
-- Nu kan du mata in Haskellkod direkt i den. Nya värden måste introduceras med
-- `let` bindning:
let foo = 5
-- Du kan även se typen av namnbindningen med `:t`
> :t foo
foo :: Integer
-- Operatorer, som `+`, `:` och `$` är funktioner. Deras typ kan inspekteras
-- genom att skriva operatorn mellan parenteser:
> :t (:)
(:) :: a -> [a] -> [a]
-- Du kan få ytterliggare information om något namn genom att använda `:i`
> :i (+)
class Num a where
(+) :: a -> a -> a
...
-- Defined in ‘GHC.Num’
infixl 6 +
-- Du kan även köra alla handlingar av typen `IO ()` direkt i tolken
> sägHej
Vad är ditt namn?
Kompis!
Hello, Kompis!
```
Det finns mycket mer att upptäcka med Haskell, inklusive typklasser och monader.
Vilka är de stora idéerna som gör Haskell till det roliga programmeringsspråket
det är. Jag lämar dig med ett sista exempel; En implementation av quicksort:
```haskell
qsort [] = []
qsort (p:xs) = qsort mindre ++ [p] ++ qsort större
where mindre = filter (< p) xs
större = filter (>= p) xs
```
Det finns två populära sätt att installera Haskell på: Den traditionella [Cabal sättet](http://www.haskell.org/platform/), eller det nyare [Stack sättet](https://www.stackage.org/install).
Du kan finna vänligare och/eller djupare introduktioner till Haskell på engelska
från:
[Learn you a Haskell](http://learnyouahaskell.com/),
[Happy Learn Haskell Tutorial](http://www.happylearnhaskelltutorial.com/) eller
[Real World Haskell](http://book.realworldhaskell.org/).
|