mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-11-29 11:22:14 +03:00
477 lines
23 KiB
Haskell
477 lines
23 KiB
Haskell
---
|
||
language: Haskell
|
||
contributors:
|
||
- ["Miltiadis Stouras", "https://github.com/mstou"]
|
||
lang: el-gr
|
||
filename: learnhaskell-gr.hs
|
||
---
|
||
|
||
Η 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/)
|