View on GitHub

dituoi_agp

Αρχές Γλωσσών Προγραμματισμού

Λίστες και πλειάδες

Δημιουργία μερικών λιστών στο ghci

Prelude> let numbers = [1,2,3,4]
Prelude> let truths  = [True, False, False]
Prelude> let strings = ["here", "are", "some", "strings"]

Τα στοιχεία μιας λίστας πρέπει να είναι του ίδιου τύπου.

Prelude> let mixed = [True, "bonjour"]

<interactive>:1:19:
    Couldn't match `Bool' against `[Char]'
      Expected type: Bool
      Inferred type: [Char]
    In the list element: "bonjour"
    In the definition of `mixed': mixed = [True, "bonjour"]

Κατασκευή μιας λίστας

Ο τελεστής (:) προφέρεται cons (από τη λέξη constructor).

Prelude> let numbers = [1,2,3,4]
Prelude> numbers
[1,2,3,4]
Prelude> 0:numbers
[0,1,2,3,4]

Παράδειγμα: cons πολλών στοιχείων σε μια λίστα.

Prelude> 1:0:numbers
[1,0,1,2,3,4]
Prelude> 2:1:0:numbers
[2,1,0,1,2,3,4]
Prelude> 5:4:3:2:1:0:numbers
[5,4,3,2,1,0,1,2,3,4]

Η κενή λίστα είναι η [] και το [1,2,3,4,5] είναι συντακτικά ισοδύναμο με 1:2:3:4:5:[].

Για την ορθή χρήση του cons πρέπει να θυμόμαστε ότι τα στοιχεία μιας λίστας πρέπει να έχουν τον ίδιο τύπο και επιτρέπεται να γίνεται ένα στοιχείο (:) σε λίστα και όχι το αντίστροφο, δηλαδή το το τελευταίο στοιχείο στα δεξιά θα πρέπει να είναι λίστα και τα στοιχεία στα αριστερά θα πρέπει να είναι στοιχεία και όχι λίστες.

Τα λεκτικά είναι απλές λίστες

Prelude> "hey" == ['h','e','y']
True
Prelude> "hey" == 'h':'e':'y':[]
True

Λίστες λιστών

Prelude> let listOfLists = [[1,2],[3,4],[5,6]]
Prelude> listOfLists
[[1,2],[3,4],[5,6]]

Πλειάδες (tuples)

Διαφορές πλειάδων και λιστών

Παραδείγματα πλειάδων

(True, 1)
("Hello world", False)
(4, 5, "Six", True, 'b')

Οι πλειάδες είναι χρήσιμες όταν θέλουμε να επιστρέφουμε περισσότερα τους ενός στοιχεία από μια συνάρτηση.

Πλειάδες μέσα σε πλειάδες (και άλλοι συνδυασμοί)

Παράδειγμα: Εμφωλευμένες πλειάδες και λίστες

((2,3), True)
((2,3), [2,3])
[(1,2), (3,4), (5,6)]

Ο τύπος μιας πλειάδας δεν ορίζεται μόνο από το μέγεθός της αλλά και από τον τύπο των αντικειμένων που περιέχει. Για παράδειγμα η πλειάδες (“Hello”,32) και (47,”World”) έχουν τύπους (String, Int) και (Int, String).

Ανάκτηση τιμών

Έστω μια πλειάδα δύο στοιχείων (ζεύγος). Το πρώτο και το δεύτερο στοιχείο της πλειάδας μπορεί να ανακτηθεί με τις συναρτήσεις fst και snd, που λειτουργούν μόνο σε ζεύγη.

Παράδειγμα χρήσης του fst και snd

Prelude> fst (2, 5)
2
Prelude> fst (True, "boo")
True
Prelude> snd (5, "Hello")
"Hello"

Για τις λίστες οι συναρτήσεις head και tail είναι ανάλογες των fst και snd. To head αποτιμάται στο πρώτο στοιχείο της λίστα και το tail στο υπόλοιπο τμήμα της λίστας.

Παράδειγμα χρήσης του head και tail

Prelude> 2:[7,5,0]
[2,7,5,0]
Prelude> head [2,7,5,0]
2
Prelude> tail [2,7,5,0]
[7,5,0]

Η εφαρμογή του head ή του tail σε μια άδεια λίστα επιστρέφει σφάλμα.

Prelude> head []
*** Exception: Prelude.head: empty list

Πολυμορφικοί τύποι

Θυμηθείτε ότι ο τύπος μιας λίστας εξαρτάται από τον τύπο των στοιχείων του και υποδηλώνεται με τετράγωνες αγκύλες.

Prelude> :t [True, False]
[True, False] :: [Bool]
Prelude> :t ["hey", "my"]
["hey", "my"] :: [[Char]]

Η συνάρτηση head έχει πολυμορφικό τύπο και αυτό της επιτρέπει να κάνει το ακόλουθο.

Prelude> head [True, False]
True
Prelude> head ["hey", "my"]
"hey"

Ο τύπος της head είναι πολυμορφικός, όπου a δεν είναι ένας τύπος, αλλά μια μεταβλητή τύπου που μπορεί να αντικαθίσταται με οποιοδήποτε τύπο. Συνεπώς, η συνάρτηση head δέχεται μια λίστα [a] από τιμές ενός οποιουδήποτε τύπου a και επιστρέφει μια τιμή του τύπου a.

:t head
head :: [a] -> a

Προσοχή στο ότι σε μια υπογραφή τύπου, όλες οι εμφανίσεις ενός τύπου μεταβλητής θα πρέπει να είναι του ίδιου τύπου. Δηλαδή η συνάρτηση f παίρνει ένα όρισμα τύπου a και επιστρέφει μια τιμή του ίδιου τύπου.

f :: a -> a

Από την άλλη ο ακόλουθος τύπος της συνάρτησης f σημαίνει ότι παίρνει μια τιμή τύπου a επιστρέφει μια τιμή που μπορεί να είναι ή καιν να μην είναι ίδιου τύπου με το a.

f :: a -> b

Παράδειγμα: fst και snd

Οι τύποι των συναρτήσεων fst και snd είναι.

fst :: (a,b) -> a
snd :: (a,b) -> b