summaryrefslogtreecommitdiffhomepage
path: root/el-gr/haskell-gr.html.markdown
blob: d2fed85ac1ca085d682a2130df26e6002681b7a7 (plain)
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
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
---
language: Haskell
filename: haskell-gr.html.markdown
contributors:
    - ["Miltiadis Stouras", "https://github.com/mstou"]
---

Η Haskell σχεδιάστηκε για να είναι μια πρακτική, αγνή συναρτησιακή γλώσσα προγραμματισμού.
Είναι διάσημη για τα monads και το σύστημα τύπων της, αλλά χρησιμοποιείται από πολλούς
κυρίως για την κομψότητά της. Προσωπικά θεωρώ ότι είναι από τις πιο όμορφες, αν όχι
η πιο όμορφη, γλώσσα προγραμματισμού.

```haskell
-- Τα σχόλια μιας γραμμής ξεκινούν με 2 παύλες.
{- Ενώ τα σχόλια πολλών γραμμών βρίσκονται
μέσα σε blocks σαν αυτό
-}

----------------------------------------------------
-- 1. Πρωτόγονοι Τύποι Δεδομένων (Primitive datatype) και Τελεστές
----------------------------------------------------

-- Οι αριθμοί είναι ένα primitive datatype
3 -- 3

-- Και οι τελεστές κάνουν αυτό που θα περιμέναμε
1 + 1 -- 2
8 - 1 -- 7
10 * 2 -- 20
35 / 5 -- 7.0

-- Η καθιερωμένη διαίρεση δεν είναι ακέραια
35 / 4 -- 8.75

-- Η ακέραια διαίρεση γίνεται με την συνάρτηση div
35 `div` 4 -- 8

-- Και οι boolean μεταβλητές ειναι primitives
True
False

-- Πράξεις με booleans
not True -- False
not False -- True
1 == 1 -- True
1 /= 1 -- False
1 < 10 -- True

-- Στα παραπάνω παραδείγματα, το `not` είναι μια συνάρτηση που παίρνει ένα όρισμα
-- Στην Haskell δεν χρειάζονται παρενθέσεις για τις κλήσεις συναρτήσεων, όλες οι παράμετροι
-- γράφονται με κενά αμέσως μετά την συνάρτηση. Στην γενική περίπτωση,
-- η κλήση συνάρτησης μοιάζει κάπως έτσι: func arg1 arg2 arg3...
-- Για το πως να ορίσετε τις δικές σας συναρτήσεις διαβάστε το κεφάλαιο των συναρτήσεων παρακάτω

-- Συμβολοσειρές και χαρακτήρες
"This is a string." -- συμβολοσειρά
'a' -- χαρακτήρας
'You cant use single quotes for strings.' -- error!
-- δεν μπορούμε να γράψουμε συμβολοσειρές ανάμεσα από ''

-- Οι συμβολοσειρές μπορούν να συννενωθούν με την χρήση του τελεστή ++
"Hello " ++ "world!" -- "Hello world!"

-- Η συμβολοσειρά είναι ουσιαστικά μια λίστα χαρακτήρων
['H', 'e', 'l', 'l', 'o'] -- "Hello"
"This is a string" !! 0 -- 'T'


----------------------------------------------------
-- 2. Λίστες και διατεταγμένα σύνολα (tuples)
----------------------------------------------------

-- Όλα τα στοιχεία μιας λίστας πρέπει να είναι του ίδιου τύπου
-- Οι δύο παρακάτω λίστες είναι οι ίδιες:
[1, 2, 3, 4, 5]
[1..5] -- διάστημα ή range

-- Τα διαστήματα μπορούν να χρησιμοποιηθούν και για άλλους τύπους εκτός από αριθμούς
['A'..'F'] -- "ABCDEF"

-- Μπορούμε ακόμη να ορίσουμε και ένα βήμα
[0,2..10] -- [0, 2, 4, 6, 8, 10]
[5..1] -- [] (Το default βήμα της Haskell είναι το 1, επομένως η διπλανή λίστα είναι κενή)
[5,4..1] -- [5, 4, 3, 2, 1]

-- Προσπέλαση στοιχείου σε τυχαία θέση
[1..10] !! 3 -- 4 (οι δείκτες των θέσεων ξεκινούν από το 0)

-- Στην Haskell υπάρχουν και άπειρες λίστες!
[1..] -- η λίστα των φυσικών αριθμών

-- Οι άπειρες λίστες μπορούν να λειτουργούν επειδή η Haksell έχει "lazy evaluation".
-- Αυτό σημαίνει ότι η Haskell κάνει υπολογισμούς μόνο όταν πραγματικά χρειάζεται!
-- οπότε αν ζητήσουμε το 1000στό στοιχείο μιας άπειρης λίστας θα μας το δώσει,
-- ξέρει ότι δεν χρειάζεται να υπολογίσει όλη την άπειρη λίστα πρώτα!

[1..] !! 999 -- 1000

-- Στο παραπάνω παράδειγμα η Haskell υπολόγισε τα στοιχεία 1 μέχρι 1000...τα υπόλοιπα
-- στοιχεία της άπειρης λίστας δεν υπάρχουν ακόμα! Η Haskell θα τα υπολογίσει
-- μόνο αν κάποια στιγμή τα χρειαστεί.

-- συνένωση δύο λιστών με τον τελεστή ++ (σε γραμμικό χρόνο)
[1..5] ++ [6..10]

-- προσθήκη στοιχείου στην αρχή της λίστας (σε σταθερό χρόνο)
0:[1..5] -- [0, 1, 2, 3, 4, 5]

-- περισσότερες συναρτήσεις για τις λίστες
head [1..5] -- 1
tail [1..5] -- [2, 3, 4, 5]
init [1..5] -- [1, 2, 3, 4]
last [1..5] -- 5

-- list comprehensions
-- ένας άλλος τρόπος να ορίζουμε τις λίστες που θυμίζει πολύ τον ορισμό συνόλων στα μαθηματικά!
[x*2 | x <- [1..5]] -- [2, 4, 6, 8, 10]

-- list comprehension με συνθήκη
[x*2 | x <- [1..5], x*2 > 4] -- [6, 8, 10]

-- Κάθε στοιχείο ενός tuple μπορεί να έχει διαφορετικό τύπο, όμως το tuple έχει σταθερό μέγεθος.
-- Ένα tuple:
("haskell", 1)

-- προσπέλαση στοιχείων ενός ζεύγους στοιχείων (δηλαδή ενός tuple μεγέθους 2)
fst ("haskell", 1) -- "haskell"
snd ("haskell", 1) -- 1

-- οι παραπάνω συναρτήσεις δεν λειτουργούν σε tuples μεγαλύτερου μεγέθους
snd ("snd", "can't touch this", "da na na na") -- error!

----------------------------------------------------
-- 3. Συναρτήσεις
----------------------------------------------------
-- Μια απλή συνάρτηση που παίρνει 2 μεταβλητές a, b και επιστρέφει το άθροισμά τους
add a b = a + b

-- Προσέξτε ότι αν χρησιμοποιείτε το διαδραστικό περιβάλλον της Haskell (ghci), δηλαδή
-- τον interpreter, θα πρέπει να προσθέσετε ενα `let` πριν τον ορισμό της συνάρτησης:
-- let add a b = a + b

-- Κλήση της συνάρτησης
add 1 2 -- 3

-- Μπορούμε να καλέσουμε την συνάρτηση και σαν τελεστή ανάμεσα στα 2 ορίσματα
-- γράφοντας το όνομα της συνάρτησης μέσα σε backticks:
1 `add` 2 -- 3

-- Μπορούμε να ορίσουμε και συναρτήσεις που δεν έχουν γράμματα στο όνομά τους!
-- Αυτό μας επιτρέπει να ορίσουμε δικούς μας τελεστές, όπως για παράδειγμα την ακέραια διάιρεση:

(//) a b = a `div` b
35 // 4 -- 8

-- Guards: ένας εύκολος τρόπος να υλοποιήσουμε διακλαδώσεις σε μια συνάρτηση
fib x
  | x < 2 = 1
  | otherwise = fib (x - 1) + fib (x - 2)

-- Το ταίριασμα προτύπων (Pattern matching) είναι παρόμοιο.
-- Εδώ δίνουμε 3 διαφορετικούς ορισμούς για την συνάρτηση fib
-- H Haskell θα χρησιμοποιήσει αυτόματα τον πρώτο ορισμό το οποίου οι παράμετροι
-- ταιριάζουν με τις παραμέτρους της κλήσης

fib 1 = 1
fib 2 = 2
fib x = fib (x - 1) + fib (x - 2)

-- Pattern matching σε tuples
sndOfTriple (_, y, _) = y
-- η κάτω παύλα χρησιμοποιείται για να μην δίνουμε ονόματα
-- σε μεταβλητές που δεν θα χρησιμοποιήσουμε και
-- ταιριάζει με όλους τους τύπους

-- Pattern matching σε λίστες.
-- Στο παρακάτω παράδειγμα, το `x` είναι το πρώτο στοιχείο της λίστας
-- και τo `xs` είναι η λίστα με τα υπόλοιπα στοιχεία

myMap func [] = []
myMap func (x:xs) = func x : (myMap func xs)

-- Μπορούμε να ορίσουμε και ανώνυμες συναρτήσεις (lambdas) χρησιμοποιώντας το
-- backslash (που μοιάζει με λ) ακολουθούμενο από τις παραμέτρους:
myMap (\x -> x + 2) [1..5] -- [3, 4, 5, 6, 7]

-- χρήση της συνάρτησης fold με μία ανώνυμη συνάρτηση
-- Το foldl1 είναι σαν fold από αριστερά, αλλά χρησιμοποιεί σαν αρχική τιμή του
-- accumulator το πρώτο στοιχείο της λίστας.
foldl1 (\acc x -> acc + x) [1..5] -- 15

----------------------------------------------------
-- 4. Περισσότερες συναρτήσεις
----------------------------------------------------

-- Μερική κλήση: αν δεν περάσουμε όλες τις μεταβλητές σε μια συνάρτηση,
-- τότε αυτή "καλείται μερικώς". Αυτό σημαίνει ότι μας επιστρέφει μια συνάρτηση
-- η οποία παίρνει ως ορίσματα τις εναπομείνασες μεταβλητές

add a b = a + b
foo = add 10 -- η foo είναι μια συνάρτηση που περιμένει 1 αριθμό και του προσθέτει 10
foo 5 -- 15

-- Ένας άλλος τρόπος να γράψουμε το ίδιο πράγμα:
foo = (10+)
foo 5 -- 15

-- Σύνθεση συναρτήσεων
-- Ο τελεστής `.` χρησιμοποιείται για την σύνθεση ("αλυσίδωση") συναρτήσεων.
-- Για παράδειγμα, η foo παρακάτω είναι μια συνάρτηση που παίρνει ως όρισμα 1 αριθμό.
-- Πρώτα προσθέτει 10 στον αριθμό που δώσαμε και μετά πολλαπλασιάζει το αποτέλεσμα με 4
foo = (4*) . (10+)

-- 4*(10+5) = 60
foo 5 -- 60

-- διόρθωση προτεραιότητας
-- Στην Haskell υπάρχει ο τελεστής `$`. Ο τελεστής αυτός εφαρμόζει μια συνάρτηση
-- σε μία παράμετρο. Σε αντίθεση με την απλή εφαρμογή συνάρτησης, η οποία έχει
-- την μεγαλύτερη πιθανή προτεραιότητα και είναι αριστερά προσεταιριστική,
-- ο τελεστής `$` έχει την ελάχιστη προτεραιότητας και είναι δεξιά προσεταιριστικός.
-- Λόγω της χαμηλής του προτεραιότητας, η έκφραση που βρίσκεται στα δεξιά του
-- θα υπολογιστεί και θα περαστεί σαν παράμετρος στην συνάρτηση που βρίσκεται στα αριστερά του


-- πριν
even (fib 7) -- false

-- ισοδύναμα
even $ fib 7 -- false

-- χρησιμοποιόντας σύνθεση συναρτήσεων
even . fib $ 7 -- false


----------------------------------------------------
-- 5. Τύποι
----------------------------------------------------

-- Η Haskell έχει ένα πολύ ισχυρό σύστημα τύπων, στο οποίο κάθε έκφραση έχει έναν τύπο

-- Κάποιο βασικοί τύποι:
5 :: Integer
"hello" :: String
True :: Bool

-- Και οι συναρτήσεις έχουν κάποιο τύπο
-- Η συνάρτηση`not` παίρνει ένα boolean και επιστρέφει ένα boolean:
-- not :: Bool -> Bool

-- Παρακάτω βλέπετε μια συνάρτηση που παίρνει 2 ορίσματα:
-- add :: Integer -> Integer -> Integer

-- Όταν ορίζουμε μια συνάρτηση ή μεταβλητή, είναι καλή πρακτική να γράφουμε
-- και τον τύπο της:
double :: Integer -> Integer
double x = x * 2

----------------------------------------------------
-- 6. Έλεγχος ροής και συνθήκες
----------------------------------------------------

-- if-expressions
haskell = if 1 == 1 then "awesome" else "awful" -- haskell = "awesome"

-- τα if-expressions μπορούν να πιάνουν και πολλές γραμμές
-- αλλά η στοίχιση είναι σημαντική!
haskell = if 1 == 1
            then "awesome"
            else "awful"

-- case expressions: Με τον παρακάτω τρόπο θα μπορούσαμε να κάνουμε parse
-- command line arguments
case args of
  "help" -> printHelp
  "start" -> startProgram
  _ -> putStrLn "bad args"

-- Η Haskell δεν έχει βρόχους επανάληψης; αντιθέτως, χρησιμοποιούμε αναδρομή.
-- Η συνάρτηση map εφαρμόζει μια συνάρτηση σε κάθε στοιχείο μιας λίστας

map (*2) [1..5] -- [2, 4, 6, 8, 10]

-- μπορούμε να κατασκευάσουμε τον βρόχο for χρησιμοποιώντας την map
for array func = map func array

-- και να τον χρησιμοποιήσουμε
for [0..5] $ \i -> show i

-- το παραπάνω θα μπορούσε να γραφτεί και έτσι:
for [0..5] show

-- Μπορούμε να χρησιμοποιήσουμε τις συναρτήσεις foldl και foldr
-- για να υπολογίζουμε μια τιμή από μια λίστα (πχ άθροισμα ή γινόμενο)
-- foldl <fn> <initial value> <list>
foldl (\x y -> 2*x + y) 4 [1,2,3] -- 43

-- Η παραπάνω κλήση είναι η ίδια με:
(2 * (2 * (2 * 4 + 1) + 2) + 3)

-- Η foldl γίνεται από τα αριστερά ενώ η foldr από τα δεξιά
foldr (\x y -> 2*x + y) 4 [1,2,3] -- 16

-- Η παραπάνω κλήση είναι τώρ:
(2 * 1 + (2 * 2 + (2 * 3 + 4)))

----------------------------------------------------
-- 7. Τύποι δεδομένων
----------------------------------------------------

-- Με τον παρακάτω τρόπο μπορούμε να ορίζουμε δικούς μας τύπους
-- δεδομένων στην Haskell

data Color = Red | Blue | Green

-- Τώρα μπορούμε να χρησιμοποιήσουμε τον τύπο μας και σε συναρτήσεις:

say :: Color -> String
say Red   = "You are Red!"
say Blue  = "You are Blue!"
say Green = "You are Green!"

-- Οι τύποι δεδομένων μας μπορεί να είναι και παραμετρικοί, να δέχονται δηλαδή
-- κάποιον τύπο ως παράμετρο

data Maybe a = Nothing | Just a

-- Όλες οι παρακάτω τιμές έχουν τύπο Maybe
Just "hello"    -- of type `Maybe String`
Just 1          -- of type `Maybe Int`
Nothing         -- of type `Maybe a` for any `a`

----------------------------------------------------
-- 8. Haskell IO
----------------------------------------------------

-- Αν και το IO δεν μπορεί να εξηγηθεί σε βάθος χωρίς να εξηγήσουμε
-- πρώτα τα monads, δεν είναι δύσκολο να το εξηγήσουμε αρκετά ώστε να μπορεί
-- κάποιος να το χρησιμοποιήσει

-- Όταν ένα πρόγραμμα Haskell εκτελείται, καλείται η συνάρτηση `main`
-- Η συνάρτηση αυτή πρέπει να επιστρέφει τύπο `IO a` για κάποιο τύπο `a`.
-- Για παράδειγμα:

main :: IO ()
main = putStrLn $ "Hello, sky! " ++ (say Blue)
-- η συνάρτηση putStrLn έχει τύπο: String -> IO ()

-- Είναι πιο εύκολο να χρησιμοποιήσουμε IO αν μπορούμε να γράψουμε το πρόγραμμά μας
-- ως μια συνάρτηση από String σε String. Η συνάρτηση
--    interact :: (String -> String) -> IO ()
-- παίρνει ως είσοδο ένα string, τρέχει μια συνάρτηση πάνω στην είσοδο
-- και τυπώνει την έξοδο

countLines :: String -> String
countLines = show . length . lines

main' = interact countLines

-- Μπορείτε να σκεφτείτε μια συνάρτηση που επιστρέφει τιμή με τύπο `IO ()`
-- ως μια ακολουθία πράξεων, περίπου όπως και σε μια imperative γλώσσα
-- Μπορούμε να χρησιμοποιήσουμε το `do` και να ενώσουμε αυτές τις κλήσεις
-- Για παράδειγμα:

sayHello :: IO ()
sayHello = do
   putStrLn "What is your name?"
   name <- getLine -- η συνάρτηση αυτή διαβάζει μια γραμμή και την αναθέτει στην μετβαλήτη name
   putStrLn $ "Hello, " ++ name

-- Δοκιμάστε να γράψετε την συνάρτηση `interact` που θα διαβάζει μια γραμμή

-- Ωστόσο ο κώδικας της συνάρτησης `sayHello` δεν θα εκτελεστεί ποτέ. Η μόνη συνάρτηση
-- που εκτελείται όταν κάνουμε compile ένα αρχείο haskell είναι η `main`.
-- Αν θέλετε να τρέξετε την sayHello (εκτός από το να φορτώσετε τον κώδικα στο
-- ghci) μπορείτε να βάλετε σε σχόλια τον προηγούμενο ορισμό της main
-- και να την ορίσετε ως:
--    main = sayHello

-- Ας προσπαθήσουμε να καταλάβουμε πως λειτουργεί η συνάρτηση `getLine`
-- Ο τύπος της είναι:
--    getLine :: IO String
-- Μπορείτε να φανταστείτε ότι μια τιμή με τύπο `IO a` θα παραχθεί
-- από ένα πρόγραμμα που παράγει μια τιμή με τύπο `a` (ενώ παράλληλα κάνει και κάτι άλλο)
-- Μπορούμε να πάρουμε και να επαναχρησιμοποιήσουμε αυτήν την τιμή χρησιμοποιώντας
-- το `<-`. Μπορούμε ακόμα και να φτιάξουμε την δική μας συνάρτηση με τύπο
-- `IO String`:

action :: IO String
action = do
   putStrLn "This is a line. Duh"
   input1 <- getLine
   input2 <- getLine
   -- Ο τύπος του `do` μπλοκ είναι εκείνος της τελευταίας γραμμής.
   -- Το `return` δεν είναι κάποια ειδική λέξη, αλλά απλώς μια συνάρτηση
   return (input1 ++ "\n" ++ input2) -- return :: String -> IO String

-- Μπορούμε να χρησιμοποιήσουμε την παραπάνω συνάρτηση ακριβώς όπως την  `getLine`:

main'' = do
    putStrLn "I will echo two lines!"
    result <- action
    putStrLn result
    putStrLn "This was all, folks!"

-- Ο τύπος `IO` είναι παράδειγμα ενός "monad". Χρησιμοποιώντας τα monads για το
-- ΙΟ, η Haskell καταφέρνει να είναι αγνή συναρτησιακή γλώσσα. Κάθε συνάρτηση που
-- αλληλεπιδρά με τον έξω κόσμο (δηλαδή κάνει IO), έχει το IO (ή κάποιο άλλο monad)
-- στον τύπο της. Αυτό μας διευκολύνει να γνωρίζουμε ποιές συναρτήσεις είναι αγνές
-- (μαθηματικές -- δεν αλληλεπιδρούν με τον έξω κόσμο ούτε αλλάζουν κάποιο state)
-- και ποιες δεν είναι.

-- Αυτό είναι ένα πολύ ισχυρό χαρακτηριστικό γιατί είναι πολύ εύκολο να
-- εκτελούμε παράλληλα αγνές συναρτήσεις! Οπότε η παραλληλοποίηση στην Haskell
-- είναι αρκετά πιο εύκολη

----------------------------------------------------
-- 9. Haskell REPL
----------------------------------------------------

-- Μπορείτε να ξεκινήσετε το διαδραστικό περιβάλλον της Haskell με την εντολή `ghci`.
-- Εδώ μπορείτε να γράψετε και να εκτελέσετε κώδικα haskell.
-- Κάθε νέα τιμή πρέπει να ορίζεται με το `let`

let foo = 5

-- Μπορείτε να βρείτε τον τύπο μιας συνάρτησης με το `:t`:

> :t foo
foo :: Integer

-- Οι τελεστές, όπως οι `+`, `:` και `$`, είναι επίσης συναρτήσεις.
-- Μπορούμε να δούμε τον τύπο τους βάζοντας τους μέσα σε παρενθέσεις:

> :t (:)
(:) :: a -> [a] -> [a]

-- Για περισσότερες πληροφορίες για οποιαδήποτε συνάρτηση ή τύπο,
-- μπορείτε να χρησιμοποιήσετε το `:i`:

> :i (+)
class Num a where
  (+) :: a -> a -> a
  ...
    -- Defined in ‘GHC.Num’
infixl 6 +

-- Μπορείτε επίσης να τρέξετε κάθε συνάρτηση με τύπο `IO ()`

> sayHello
What is your name?
Friend!
Hello, Friend!

```

Υπάρχουν πολλά ακόμα πράγματα να εξερευνήσετε στην Haskell, όπως τα typeclasses
και διάφορα monads! Αυτές οι μαθηματικά ορισμένες έννοιες είναι που κάνουν την
Haskell αυστηρή, αγνή και κομψή! Θα τελειώσουμε αυτήν την σύντομη περιήγηση με
ένα τελευταίο παράδειγμα, η υλοποίηση της QuickSort σε Haskell:

```haskell
qsort [] = []
qsort (p:xs) = qsort lesser ++ [p] ++ qsort greater
    where lesser  = filter (< p) xs
          greater = filter (>= p) xs
```

Υπάρχουν 2 παραδοσιακοί τρόποι να εγκαταστήσετε την Haskell:
- [Cabal-based installation](http://www.haskell.org/platform/),
- [Stack-based process](https://www.stackage.org/install).

Στις παρακάτω πηγές μπορείτε να βρείτε αρκετά κομψές εισαγωγές στην Haskell
- [Learn you a Haskell](http://learnyouahaskell.com/),
- [Happy Learn Haskell Tutorial](http://www.happylearnhaskelltutorial.com/),
- [Real World Haskell](http://book.realworldhaskell.org/)