View on GitHub

dituoi_agp

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

Βασικές έννοιες τύπων ΙΙ

Αναρωτηθείτε ποιος είναι ο τύπος της συνάρτησης (+) χωρίς ακόμα να χρησιμοποιήσετε την :type;

Θα μπορούσε να είναι;

(+) :: Number -> Number -> Number

Όχι, διότι κάθε τύπος αριθμού (π.χ. ακέραιος, πραγματικός) αντιστοιχεί σε διαφορετικό τύπο της Haskell.

Θα μπορούσε να είναι ορισμένη πολυμορφικά;

(+) :: a -> a -> a

Όχι, διότι τότε η συνάρτηση (+) θα εφαρμόζονταν σε οποιαδήποτε ορίσματα του ίδιου τύπου, π.χ. Bool ή Char που δεν θα ήταν σωστό.

Ο τύπος που επιστρέφει η Haskell είναι.

(+) :: (Num a) => a -> a -> a

όπου Num είναι ένα typeclass — μια ομαδοποίηση τύπων — που περιέχει όλους τους τύπους που μπορούν να θεωρηθούν ως αριθμοί. Το τμήμα (Num a) => τηε υπογραφής της συνάρτησης περιορίζει το a σε αριθμητικούς τύπους (σε στιγμιότυπα της Num).

Αριθμητικοί τύποι

Οι σημαντικότεροι αριθμητικοί τύποι (που είναι στιγμιότυπα της Num) είναι οι Int (έχει περιορισμούς εύρους τιμών), Integer (υποστηρίζει μεγάλους αριθμούς), Double.

Prelude> (-7) + 5.12
-1.88
Prelude> :t (-7)
(-7) :: (Num a) => a

Η τιμή (-7) δεν είναι ούτε Int, ούτε Integer, αλλά μια πολυμορφική τιμή που μπορεί να μετασχηματιστεί σε οποιαδήποτε αριθμητικό τύπο.

Prelude> :t 5.12
5.12 :: (Fractional t) => t

Η τιμή 5.12 επίσης δεν είναι Double (ή Float), αλλά μια πολυμορφική τιμή της κλάσης Fractional που είναι υποκλάση του τύπου Num.

Στην πράξη (-7) + 5.12 η Haskell με την επαγωγή τύπων (type inference) θα συμπεράνει ότι το (-7) είναι οποιουδήποτε τύπου Num, αλλά λαμβάνοντας υπόψη τους περιορισμούς του 5.12 θα συμπεράνει ότι ο τύπος του είναι ο προκαθορισμένος για τον τύπο Fractional (υποκλάση του Num), δηλαδή ο Double (υποκλάση του Fractional). Για να γίνει η πράξη και το (-7) θα γίνει Double (υποκλάση του Num).

x = 2

monitor_type1.hs

Prelude> :load monitor_type1.hs

:type x
x :: Integer
x = 2
y = x + 3

monitor_type2.hs

Prelude> :load monitor_type2.hs

:type x
x :: Integer
:type y
y :: Integer
x = 2
y = x + 3.1

monitor_type3.hs

Prelude> :load monitor_type3.hs

:type x
x :: Double
:type y
y :: Double

Μονομορφικά προβλήματα

Ο τύπος του () είναι.

 Prelude> :type (/)
(/) :: Fractional a => a -> a -> a

Οι πολυμορφικές τιμές 4 και 3 θα λάβουν τύπο Double λόγω του /

Prelude> 4 / 3
1.3333333333333333

Ωστόσο αυτό δεν μπορεί να γίνει στο ακόλουθο (δηλαδή η διαίρεση της ακέραιας τιμής 4 με το μήκος της λίστας [1,2,3]).

Prelude> length [1,2,3]
3
Prelude> 4 / length [1,2,3]
<interactive>:1:0:
    No instance for (Fractional Int)
      arising from a use of `/' at <interactive>:1:0-17
    Possible fix: add an instance declaration for (Fractional Int)
    In the expression: 4 / length [1, 2, 3]
    In the definition of `it': it = 4 / length [1, 2, 3]

λόγω του ότι ο τύπος του length είναι ο ακόλουθος που επιστρέφει τιμή τύπου Int (μη πολυμορφικός τύπος που δεν είναι στιγμιότυπο του Fractional).

:type length
length :: Foldable t => t a -> Int

Το πρόβλημα λύνεται ως εξής.

Prelude> 4 / fromIntegral (length [1,2,3])
1.3333333333333333

χρησιμοποιώντας τη συνάρτηση fromIntegral που έχει τύπο που λαμβάνει μια τιμή Integral (π.χ. Int, Integer) και επιστρέφει μια πολυμορφική τιμή.

fromIntegral :: (Integral a, Num b) => a -> b

Κλάσεις πέρα από αριθμούς

Το παράδειγμα του Eq

H Haskell διαθέτει και άλλα typeclasses πέρα από τα typeclasses των αριθμών. Για παράδειγμα στην υπογραφή του (==) εμφανίζεται το typeclass Eq που αφορά τιμές που μπορούν να συγκριθούν για ισότητα.

(==) :: (Eq a) => a -> a -> Bool

Το παράδειγμα του Foldable

Επίσης, η συνάρτηση length δέχεται ως όρισμα μια τιμή του typeclass Foldable που είναι μια γενίκευση δομών ομαδοποίησης τιμών (υποκλάση της Foldable είναι και η λίστα [a]).