Haskell
Εισαγωγή στη γλώσσα Haskell ØΕίναι µια καινοτόµα συναρτησιακή γλώσσα προγραµµατισµού γενικής χρήσεως µε µη αυστηρή σηµασιολογία και ισχυρούς τύπους. ØΕίναι περισσότερο ευέλικτη και δυναµική γλώσσα σε σχέση µε τις παραδοσιακές γλώσσες προγραµµατισµού.
Ιστορία ØΗ Haskell πήρε το όνοµα της από τον αµερικάνο επιστήµονα λογικής και µαθηµατικών Haskell Brooks Curry και βασίστηκε πάνω στις παρατηρήσεις του. Ø1990: Πρώτη έκδοση Haskell 1.0 Ø1998: Haskell 98 Ø2010: αναθεωρηµένη έκδοση Haskell 2010.
Πλεονεκτήµατα ØΛύνεται ένα πρόβληµα µε συστηµατικό(µαθηµατικό) τρόπο. Ø Αυξάνεται η παραγωγικότητα του προγραµµατιστή Ø Μειώνονται σηµαντικά τα σφάλµατα και ο προγραµµατιστικός χρόνος. ØΈχει οκνηρή αποτίµηση, δηλαδή δεν υπολογίζει κάτι εκτός κι αν αυτό είναι απολύτως απαραίτητο. Έτσι, αν κάποιοι υπολογισµοί δεν είναι απαραίτητοι δεν γίνονται καθόλου. ØΕυκολότερος ο εντοπισµός λαθών
Μειονεκτήµατα ØΠολλά χαρακτηριστικά της γλώσσας είναι αρκετά περίπλοκα και σύνθετα ØΣυχνά είναι αρκετά δύσκολο να αποφανθούµε για την απόδοση των προγραµµάτων σε σχέση µε την ταχύτητα και την χρήση της µνήµης. ØΔεν µπορεί να είναι πιο γρήγορη από ένα καλογραµµένο πρόγραµµα σε µια χαµηλού επιπέδου γλώσσα όπως η C.
Εφαρµογές σε Haskell Ø Darcs: ένα σύστηµα διαχείρισης εκδόσεων Ø Tα εργαλεία του συστήµατος στην διανοµή GNU/Linux αναπτύχθηκαν σε Haskell Ø Ο Xmonad(ο διαχειριστής παραθύρων για τα X WINDOWS SYSTEM) είναι γραµµένος αποκλειστικά σε Haskell Ø Τα εργαλεία της Bluespec
Πρόσβαση στη γλώσσα Haskell ØΗ χρήση της γλώσσας προγραµµατισµού Haskell προϋποθέτει την ύπαρξη ενός διερµηνέα ή ενός µεταγλωττιστή της Haskell. ØΟ διερµηνέας παρουσιάζει µια κονσόλα, στην οποία ο χρήστης έχει την δυνατότητα να πληκτρολογήσει εκφράσεις Haskell προς αποτίµηση ή εντολές που κατευθύνονται στον διερµηνέα.
Μεταγλωττιστές ØΟι πιο διάσηµοι µεταγλωττιστές της γλώσσας Haskell είναι οι παρακάτω: Haskell Platform Glasgow Haskell Compiler(GHC) Utrecht Haskell Compiler (UHC) Hugs ( Haskell User's Gofer System) Nhc98 HBC
Αποτίµηση των εκφράσεων της Haskell Μια έκφραση της γλώσσας προγραµµατισµού της Haskell µπορεί να είναι ένα από τα εξής: Ø Μια σταθερά. Για ορισµένες σταθερές που υποστηρίζονται από τη Haskell. Ø Ένας τελεστής. Μοναδιαίος τελεστής: ο τελεστής που παίρνει µόνο ένα όρισµα. Δυαδικός τελεστής: τελεστής που παίρνει δυο ορίσµατα.
Αποτίµηση των εκφράσεων της Haskell ØΜια συνάρτηση. ØΜια έκφραση µέσα σε παρένθεση. ØΈνα αναγνωριστικό. Τα αναγνωριστικά συµβολίζουν τιµές που στις εκφράσεις αρχίζουν µε πεζό λατινικό γράµµα και περιέχουν λατινικά γράµµατα και αριθµούς.
Σηµείωση ØΛέξεις- κλειδιά της Haskell δεν µπορούν να χρησιµοποιηθούν ως αναγνωριστικά. ØΌταν δίνουµε µια έκφραση στον διερµηνέα, ο διερµηνέας την αποτιµά και επιστρέφει το αποτέλεσµα. Για παράδειγµα, εάν δώσουµε στον διερµηνέα την έκφραση 2-2*4 η αποτίµηση της έκφρασης θα µας επιστρέψει το αποτέλεσµα 6.
Βασικοί τύποι της Haskell ØΚάθε έκφραση αντιστοιχεί σε έναν τύπο, ο οποίος χαρακτηρίζει το είδος της τιµής που αναπαρίσταται από την εκάστοτε έκφραση. ØΥπάρχουν τέσσερις βασικοί τύποι της Γλώσσας Haskell: Bool (=αληθοτιµές, λογικές τιµές) Int (=ακέραιοι αριθµοί) Float (=αριθµοί κινητής υποδιαστολής) Char (=χαρακτήρες)
Bool Ø Η χρήση του τύπου Bool αναπαριστά τις αληθοτιµές, δηλαδή τις λογικές τιµές. Ø Λαµβάνουν δυο σταθερές (τιµές): True False
Βool ØΟι τελεστές που υποστηρίζονται από τον τύπο Bool είναι οι εξής: == (λογική ισοδυναµία, ισότητα) Δυαδικοί && (λογική σύζευξη) ΙΙ (λογική διάζευξη) /= (ανισότητα, αποκλειστική λογική διάζευξη) Μοναδιαίος not (λογική άρνηση)
Bool ØΗ τιµή της έκφρασης a && b είναι True εάν και µόνο εάν το a και το b είναι True ØΗ τιµή της έκφρασης a b είναι True εάν ένα τουλάχιστον από τα a και b είναι True ØΗ τιµή της έκφρασης not a είναι True αν το a είναι False και είναι False αν το a είναι True
Int ØΗ χρήση του τύπου Int αναπαριστά τον τύπο των ακέραιων αριθµών. ØΠεριλαµβάνονται θετικοί και αρνητικοί αριθµοί. ØΠαραθέτοντας δεκαδικά ψηφία έχουµε τη δυνατότητα να δηµιουργήσουµε σταθερές αυτού του τύπου. ØΕπιτρέπεται η χρήση του µοναδιαίου τελεστή για τη κατασκευή αρνητικών αριθµών.
Δυαδικοί τελεστές για τον τύπο Int Ø+ (Πρόσθεση) Ø- (αφαίρεση) Ø^ (ύψωση) Ø* (πολλαπλασιασµός)
Συναρτήσεις για τον τύπο Int ØDiv (ακέραια διαίρεση) ØMod (υπόλοιπο ακέραιας διαίρεσης) ØAbs (απόλυτη τιµή ορίσµατος) ØRem (υπόλοιπο)
Float ØΑναπαριστά τους αριθµούς κινητής υποδιαστολής, δηλαδή αριθµούς που δεν είναι κατά ανάγκη ακέραιοι.
Σταθερές του τύπου Float ØΧρήση υποδιαστολής (π.χ. 0.5 ) ή ØΕπιστηµονικό συµβολισµό aeb, όπου a ένας αριθµός κινητής υποδιαστολής και b ένας ακέραιος αριθµός. Το παραπάνω συµβολίζει τον αριθµό 10ᵇa. (π.χ. η σταθερά 5.0e-3 συµβολίζει τον αριθµό 0.005).
Float ØΟι τελεστές + (πρόσθεση),- (αφαίρεση) και * (πολλαπλασιασµός) καθώς και όλοι οι τελεστές σύγκρισης υποστηρίζονται από τον τύπο Float. ØΩστόσο, ο τελεστής / συµβολίζει την κανονική διαίρεση.
Συναρτήσεις για τον τύπο Float Øabs(απόλυτη τιµή) Øcos(συνηµίτονο) Øsin(ηµίτονο) Øtan(εφαπτοµένη) Øsqrt(τετραγωνική ρίζα) Øceiling floor round (µετατροπή στον µεγαλύτερο, µικρότερο και πλησιέστερο ακέραιο αριθµό) Ølog(λογάριθµος µε βάση το e) ØfromIntegral(µετατρέπει έναν ακέραιο αριθµό σε αριθµό κινητής υποδιαστολής).
Σηµείωση ØΑξίζει να σηµειωθεί, ότι σε αντίθεση µε τις περισσότερες γλώσσες προγραµµατισµού, στη Haskell, δεν συµβαίνουν αυτόµατες µετατροπές ανάµεσα στους τύπους Int και Float.
Char Η χρήση του τύπου Char αναπαριστά τους χαρακτήρες. Σταθερές του τύπου Char: ØΈνας χαρακτήρας που περικλίεται σε µονά εισαγωγικά (π.χ a, b ). ØΕιδικοί χαρακτήρες: \t (tab) \n (νέα γραµµή) \\ (backslash (\)) \ (µονό εισαγωγικό ( )) \ (διπλό εισαγωγικό ( ))
Συναρτήσεις Ø Ο τρόπος µε τον οποίο προγραµµατίζουµε σε γλώσσα Haskell είναι ο ορισµός συναρτήσεων. Σύνθεση συναρτήσεων(composition): χρήσιµος τελεστής, συµβολίζεται µε «.». Συναρτήσεις ανώτερης τάξης: Οι συναρτήσεις µπορούν να περάσουν σε άλλες συναρτήσεις ως ορίσµατα. Η συνάρτηση που δέχεται ως όρισµα άλλες συναρτήσεις ονοµάζεται συνάρτηση ανώτερης τάξης. Προσοχή βάζουµε τον τύπο της συνάρτησηςορίσµατος µέσα σε παρενθέσεις. Το πλεονέκτηµα των συναρτήσεων υψηλής τάξης είναι η αποφυγή παρόµοιου κώδικα για παρόµοιες λειτουργίες.
Γενική µορφή µιας συνάρτησης Haskell f pat1 patn =E Το καθένα από τα pat1 patn µπορεί να είναι µεταβλητές, σταθερές τιµές ή να έχει µια πιο πολύπλοκη µορφή. Ονοµάζεται πρότυπο(pattern) και συµβολίζει ένα όρισµα συνάρτησης. Το Ε είναι η έκφραση της γλώσσας. Μια συνάρτηση µπορεί να οριστεί και µε περισσότερες από µια εξισώσεις.
Παράδειγµα ØΗ συνάρτηση add είναι µια συνάρτηση δύο ακέραιων ορισµάτων που δίνει ένα ακέραιο αποτέλεσµα. ØΔηλαδή: αdd::int_>int->int
Γραφή Προγράµµατος σε Haskell Για να δηµιουργήσουµε ένα πρόγραµµα σε Haskell, πρέπει πρώτα να ορίσουµε δικές µας τιµές σε νέα ονόµατα. Για να ορίσουµε τιµές θα πρέπει να δηµιουργήσουµε µέσα στον φάκελο που δουλεύουµε ένα αρχείο µε κατάληξη.hs (Haskell scripts). Για να φορτώσουµε τους ορισµούς του αρχείου χρησιµοποιούµε την εντολή :load <όνοµα του αρχείου>, χωρίς την κατάληξη.hs.
Γραφή Προγράµµατος σε Haskell ØΜπορούµε να γράψουµε ένα σχόλιο στο πρόγραµµα µας, χρησιµοποιώντας δύο παύλες (--) στην αρχή της γραµµής. ØΜπορούµε να τερµατίσουµε µια πρόταση µε τον χαρακτήρα «;».
Πρόγραµµα Haskell Παραδείγµατος χάρη, φτιάχνουµε ένα αρχείο FirstProject.hs στον τρέχων φάκελο και το περιεχόµενο του θα είναι : i :: Int --Δηλώνουµε το i integer i = 1 -- Δίνουµε στο i τιµή 1 j :: Int -- Δηλώνουµε το j integer j = 5 -- Δίνουµε στο j τιµή 5 start n= if (n<10) then n+1+i-j else n-1-i+j
Πρόγραµµα Haskell Κάνουµε :load FirstProject και εκτελούµε την εντολή start<έναν αριθµό> Π.Χ.(start 3). Το πρόγραµµα εκτελείτε και βλέπουµε το αποτέλεσµα της πράξης µας. 0 διότι η πράξη εκτελείτε ως start n= 3 if (n<10) --ελέγχει αν το 3 είναι µικρότερο του 10 then n+1+i-j -- εκτελείτε διότι είναι αληθής η if -- 3+1+1-5 =0 else n-1-i+j -- δεν εκτελείτε
Πλειάδες (tuples) Οι πλειάδες προσφέρουν έναν άλλο τρόπο για την αποθήκευση πολλαπλών τιµών σε µια ενιαία τιµή. Οι πλειάδες και οι λίστες έχουν 2 βασικές διαφορές : Οι πλειάδες έχουν ένα σταθερό αριθµό στοιχείων(αµετάβλητο). Τα στοιχεία µιας πλειάδας δεν χρειάζεται να είναι όλα του ίδιου τύπου.
Λίστες(lists) ØΕίναι σειρές οµογενών δεδοµένων µεταβλητού µεγέθους ØΙδιαίτερη σηµασία έχει η σειρά και ο αριθµός εµφάνισης των στοιχείων.
Τρόποι γραφής µιας λίστας ØΚενή λίστα [] η απλούστερη µορφή λίστας ØΑπαρίθµηση στοιχείων της λίστας [1,2,3] ØΧρήση τελεστή : [1,2,3]=1:[2,3]=1:(2:[3])=1:(2:(3:[])) ΣΗΜΕΙΩΣΗ: Όλα τα στοιχεία µιας λίστας θα πρέπει να έχουν τον ίδιο τύπο!!!! (π.χ. όλα ακέραιοι αριθµοί)
Συναρτήσεις της Haskell για λίστες ØΠροσθήκη κεφαλής (:) e : gd = egd ØΣυνένωση πολλών λιστών concat [[],[5,9],[3]] = [5,9,3] ØΜέγεθος λίστας length length hellο:) = 7 ØΣυνένωση (++) [5,8,3] ++[6,9,4] =[5,8,3,6,9,4] ØΚεφαλή (head) /τελευταίο στοιχείο (last) head l =l!!0 head l=l!!(length l-1)
Συναρτήσεις της Haskell για λίστες ØΟυρά (tail) / πρώτα στοιχεία (init) tail[5,1,9] = [1,9] init[3,6,7]=[3,6] ØΕπιλογή (take)/ απόρριψη αριθµού στοιχείων (drop) take 5 [1..10] = [1,2,3,4,5] drop 6 [1,5,7,4,9,12,59,78,45,18,20,25,] = [1,5,7,4,9,12]
Συναρτήσεις της Haskell για λίστες ØΣπάσιµο λίστας (splitat) splitat (5) [-4..4]=([- 4,-3,-2,-1,0],[1,2,3,4]) ØΕπανάληψη (replicate) replicate 1 3 = 111 ØΦιλτράρισµα λίστας (filter) filter (>0) [-4..4]=[1,2,3,4] ØZipping (zip) zip "Haskell" [5,4,3] = [('H',5),('a',4),('s',3)]
Συναρτήσεις της Haskell για λίστες ØUnzipping (unzip) unzip [('H',5),('a',4),('s',3)]= ("Has",[5,4,3]) ØΕπιλογή (takewhile)/απόρριψη µε συνθήκη (dropwhile) takewhile (<3) [1,2,3,4,5] = [1,2] dropwhile (<3) [1,2,3,4,5] = [3,4,5] ØΣυσσωρευτικός υπολογισµός (folding) foldl και foldr foldl (-) 0 [1,3,2] = ((0-1)-3)-2 = -6 foldr (-) 0 [1,5,8] = (1-(5-8))-0 = 4
Παράδειγµα υπολογισµού µήκους λίστας Ølength [1,2,3,4,5]=1+length[2,3,4,5] =1+(1+length[3,4,5]) =1+(1+(1+length[4,5])) =1+(1+(1+(1+length[5]))) =1+(1+(1+(1+(1+length[])))) =1+(1+(1+(1+(1+0)))) =5
Αναδροµικά προγράµµατα µε λίστες ØΗ αναδροµή αποτελεί βασική τεχνική στις συναρτησιακές γλώσσες προγραµµατισµού. ØΧρησιµοποιείται για τον ορισµό συναρτήσεων που επεξεργάζονται διάφορους τύπους δεδοµένων. ØΣτα αναδροµικά προγράµµατα µε λίστες χρησιµοποιείται: Το πρότυπο [] για κενές λίστες Το x:xs για µη κενές λίστες
Συµβολοσειρές Ø Είναι λίστες χαρακτήρων. ØΣυµβολίζονται µε String που αποτελεί συντοµογραφία του τύπου [char] ØΤις γράφουµε σαν ακολουθίες που περικλείονται µέσα σε διπλά εισαγωγικά
Εκφράσεις Διαχωρισµού (list comprehension) Øδηµιουργία µιας λίστας µε µετασχηµατισµό και φιλτράρισµα στοιχείων άλλων λιστών
Απόκρυψη ονοµάτων ØΣυµβάλλει στην τµηµατοποίηση του κώδικα και στην αποδοτικότητα των υπολογισµών ØΜηχανισµοί: Ορατά ονόµατα σε έναν ορισµό: where Ορατά ονόµασε σε µια έκφραση: let Ανώνυµες συναρτήσεις: λ-εκφράσεις Ø ΠΡΟΣΟΧΗ: κανόνας αποφυγής συγκρούσεων ονοµάτων
3D Demo
3D Demo Cube.hs module Cube where import Graphics.UI.GLUT vertex3f :: (GLfloat, GLfloat, GLfloat) -> IO () vertex3f (x, y, z) = vertex $ Vertex3 x y z cube :: GLfloat -> IO () cube w = renderprimitive Quads $ mapm_ vertex3f [ ( w, w, w), ( w, w,-w), ( w,-w,-w), ( w,-w, w), ( w, w, w), ( w, w,-w), (-w, w,-w), (-w, w, w), ( w, w, w), ( w,-w, w), (-w,-w, w), (-w, w, w), (-w, w, w), (-w, w,-w), (-w,-w,-w), (-w,-w, w), ( w,-w, w), ( w,-w,-w), (-w,-w,-w), (-w,-w, w), ( w, w,-w), ( w,-w,-w), (-w,-w,-w), (-w, w,-w) ] cubeframe :: GLfloat -> IO () cubeframe w = renderprimitive Lines $ mapm_ vertex3f [ ( w,-w, w), ( w, w, w), ( w, w, w), (-w, w, w), (-w, w, w), (-w,-w, w), (-w,-w, w), ( w,-w, w), ( w,-w, w), ( w,-w,-w), ( w, w, w), ( w, w,-w), (-w, w, w), (-w, w,-w), (-w,-w, w), (-w,-w,-w), ( w,-w,-w), ( w, w,-w), ( w, w,-w), (-w, w,-w), (-w, w,-w), (-w,-w,-w), (-w,-w,-w), ( w,-w,-w) ] MainProg.hs import Graphics.UI.GLUT import Data.IORef import Bindings main :: IO () main = do (_progname, _args) <- getargsandinitialize initialdisplaymode $= [WithDepthBuffer, DoubleBuffered] _window <- createwindow"graphics window" --Δηµιουργία windows reshapecallback $= Just reshape -- depthfunc $= Just Less angle <- newioref 0 delta <- newioref 0.1 pos <- newioref (0, 0) keyboardmousecallback $= Just (keyboardmouse delta pos) idlecallback $= Just (idle angle delta) displaycallback $= display angle pos mainloop
3D Demo Bindings.hs module Bindings (idle, display, reshape, keyboardmouse) where import Graphics.UI.GLUT import Data.IORef import Display reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) keyboardmouse :: IORef GLfloat -> IORef (GLfloat, GLfloat) -> KeyboardMouseCallback keyboardmouse a p key Down = case key of (Char ' ') -> a $~! negate (Char '+') -> a $~! (* 2) (Char '-') -> a $~! (/ 2) (SpecialKey KeyLeft ) -> p $~! \(x,y) -> (x-0.1,y) (SpecialKey KeyRight) -> p $~! \(x,y) -> (x+0.1,y) (SpecialKey KeyUp ) -> p $~! \(x,y) -> (x,y+0.1) (SpecialKey KeyDown ) -> p $~! \(x,y) -> (x,y-0.1) _ -> return () keyboardmouse = return () Points.hs module Points where import Graphics.Rendering.OpenGL points :: Int -> [(GLfloat,GLfloat,GLfloat)] points n = [ (sin (2*pi*k/n'), cos (2*pi*k/n'), 0) k <- [1..n'] ] where n' = fromintegral n
3D Demo Display.hs module Display (idle, display) where import Graphics.UI.GLUT import Control.Monad import Data.IORef import Cube import Points display :: IORef GLfloat -> IORef (GLfloat, GLfloat) -> DisplayCallback display angle pos = do clear [ColorBuffer, DepthBuffer] -- clear depth buffer, too clear [ColorBuffer] loadidentity (x',y') <- get pos translate $ Vector3 x' y' 0 preservingmatrix $ do a <- get angle rotate a $ Vector3 0 0 1 rotate a $ Vector3 0 0.1 1 -- changed y-component a bit to show off cube corners scale 0.7 0.7 (0.7::GLfloat) form_ (points 6) $ \(x,y,z) -> preservingmatrix $ do color $ Color3 ((x+1)/2) ((y+1)/2) ((z+1)/2) translate $ Vector3 x y z cube 0.25 color $ Color3 (0::GLfloat) 0 0 -- set outline color to black cubeframe 0.1 -- draw the outline swapbuffers idle :: IORef GLfloat -> IORef GLfloat -> IdleCallback idle angle delta = do d <- get delta angle $~! (+ d) postredisplay Nothing
Πηγές Δικτυογραφία Ø Κοινότητα Ελεύθερου Λογισµικού ΕΜΠ (https://foss.ntua.gr/wiki/index.ph p) Ø Haskell: Βασικές δοµές και απόκρυψη oνοµάτων (Γιάννης Κασσιός)(http://cgi.di.uoa.gr/~kassios/c ourses/fp/slides/pres_2.pdf) Ø Εισαγωγή στη γλώσσα Haskell(Γιάννης Κασσιός)(http://cgi.di.uoa.gr/~kassios/c ourses/fp/notes/1.pdf) Ø Συναρτησιακός Προγραµµατισµός: Η Γλώσσα Haskell(Π. Ροντογιάννης)(http://cgi.di.uoa.gr/~pro ndo/languages/languages.html) Βιβλιογραφία Ø Real World Haskell (Jobn Goerzen & Don stewari)
ΣΑΣ ΕΥΧΑΡΙΣΤΩ ΠΟΛΥ ΓΙΑ ΤΗΝ ΠΡΟΣΟΧΗ ΣΑΣ.