Funkcionális Nyelvek 2 (MSc) Páli Gábor János pgj@elte.hu Eötvös Loránd Tudományegyetem Informatikai Kar Programozási Nyelvek és Fordítóprogramok Tanszék
Tematika
A (tervezett) tematika rövid összefoglalása http://people.inf.elte.hu/pgj/fny2_msc/ Monádok, monádtípusok, ezek kombinációja Tulajdonságalapú tesztelés Konkurens és párhuzamos programozás (tisztán funkcionális nyelvben) Perzisztens (tisztán funkcionális) adatszerkezetek Hatékonyság funkcionális nyelvekben Beágyazott nyelvek Interaktív funkcionális programok [3..30]
Monádok
Programozás monádokkal bevezetés https://byorgey.wordpress.com/2009/01/12/ abstraction-intuition-and-the-monad-tutorial-fallacy/ [5..30]
Programozás burritokkal [6..30]
Programozás burritokkal [7..30]
Programozás burritokkal [8..30]
Programozás burritokkal [9..30]
Programozás burritokkal [10..30]
Programozás burritokkal [11..30]
Programozás burritokkal [12..30]
Mi nem a monád? A következő állítások mindegyike hamis: A monádok nem tisztán funkcionálisak. A monádok programbeli hatásokat modelleznek. A monádok az állapotról szólnak. A monádok utasítások sorbarendezését teszik lehetővé. A monádok az I/O-t modellezik. A monádok működéséhez szükséges a lusta kiértékelés. A monádok segítségével lehet trükkösen mellékhatásokat használni. A monádok egy beágyazott nyelv a Haskelleben belül. A monádokat csak matematikusok érthetik meg. [13..30]
A monád fogalmának megértése 8 egyszerű lépésben 1. Ne olvassuk tutorialokat! 2. Ne olvassuk tutorialokat! 3. Tanuljunk a Haskell típusairól ( Nyelvek típusrendszere tárgy)! 4. Tanuljuk meg a típusosztályokat ( Funkcionális nyelvek tárgy)! 5. Tanulmányozzuk a Typeclassopediát! 6. Tanulmányozzuk a monádok definícióját! 7. Programozzunk monádokkal ( beadandók)! 8. Ne írjunk tutorialokat! http://www.cs.tufts.edu/comp/150fp/archive/ brent-yorgey/tc.pdf [14..30]
Programozás monádokkal programstruktúrálás Tegyük fel, hogy meg szeretnénk írni egy tisztán funkcionális nyelven az alábbi algoritmussal rendelkező programot: Írjuk ki a képernyőre, hogy "Provide me a word> ". Olvassuk be a felhasználó által begépelt szót. Az adott szótól függően tegyük a következőt: Ha palindróma, akkor írjuk ki a képernyőre, hogy "Palindrome." Ha nem palindróma, akkor írjuk ki a képernyőre, hogy "Not a palindrome." Adottak: putstr :: String -> World -> World getline :: World -> (String, World) [15..30]
Programozás monádokkal programstruktúrálás ($) :: (a -> b) -> a -> b f $ x = f x program :: World -> World program w = (\(s, w) -> if (s == reverse s) then putstr "A palindrome." w else putstr "Not a palindrome." w) $ getline $ putstr "Provide me a word> " $ w [16..30]
Programozás monádokkal programstruktúrálás ( >) :: a -> (a -> b) -> b x > f = f x program :: World -> World program w = w > putstr "Provide me a word> " > getline > \(s, w) -> if (s == reverse s) then putstr "A palindrome." w else putstr "Not a palindrome." w [17..30]
Programozás monádokkal programstruktúrálás type IO a = World -> (a, World) -- putstr :: String -> IO () -- getline :: IO String (>>=) :: IO a -> (a -> IO b) -> IO b (f >>= g) w = (g x) w where (x, w ) = f w (>>) :: IO a -> IO b -> IO b f >> g = f >>= \_ -> g program :: IO () program = putstr "Provide me a word> " >> getline >>= \s -> if (s == reverse s) then putstr "A palindrome." else putstr "Not a palindrome." [18..30]
Programozás monádokkal programstruktúrálás main :: IO () main = do putstr "Provide me a word> " s <- getline if (s == reverse s) then putstr "A palindrome." else putstr "Not a palindrome." [19..30]
Programozás monádokkal a Monad típusosztály -- Control.Monad class Monad (m :: * -> *) where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b x >> f = x >>= \_ -> f fail :: String -> m a fail s = error s (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c) f >=> g = \x -> f x >>= g return >=> f === f f >=> return === f (f >=> g) >=> h === f >=> (g >=> h) + run függvény [20..30]
Programozás monádokkal a do szintaktika Átírási szabályok: do { e1; e2 } --> e1 >> do { e2 } do { p <- e1; e2 } --> e1 >>= \x -> case x of p -> do { e2 } _ -> fail "error" do { let p = e1; e2 } --> let p = e1 in do { e2 } do { e } --> e Például: do { do x <- f; x <- f f >>= \x -> y <- g; y <- g g >>= \y -> z <- h; --> z <- h --> h >>= \z -> let t = (x,y,z); let t = (x,y,z) let t = (x,y,z) in return t return t return t } [21..30]
Milyen monádok léteznek? data IO a =? Az IO monáddal tetszöleges mellékhatást tudunk modellezni, ez a "jolly joker". Például: putstrln: írás a szabványos kimenetre getline: olvasás a szabványos bemenetröl IORef: módosítható hivatkozások, mutatók IOError: kivétel(kezelés) IOArray: hatékony, felülírható elemeket tartalmazó tömb forkio: (konkurens) szálak létrehozása run függvény: a futtató rendszer, unsafeperformio [22..30]
Ilyen monádok léteznek? data [a] = [] a:[a] instance Monad [] where return x = [x] xs >>= f = concat [ f x x <- xs ] fail _ = [] multiplytonm :: (Num a, Eq a, Enum a) => a -> [(a,a)] multiplytonm n = do x <- [1..n] y <- [x..n] if (x * y == n) then return (x,y) else fail "Not applicable." multiplyton n = [ (x,y) x <- [1..n], y <- [x..n], x * y == n ] [23..30]
Az Identity monád type Identity a = a -- a -> (a -> b) -> b (>>=) :: Identity a -> (a -> Identity b) -> Identity b x >>= f = f x -- a -> a return :: a -> Identity a return x = x -- a -> a runidentity :: Identity a -> a runidentity x = x [24..30]
Az Identity monád -- Control.Monad.Identity data Identity a = I a runidentity :: Identity a -> a runidentity (I x) = x instance Monad Identity where return x = I x x >>= f = f (runidentity x) [25..30]
Az Identity monád (példa) m :: Int -> Identity Int m x = return (x * x) m :: Int -> Identity Int m x = do return (x * x) return (x * 2) return (x * 3) m :: Int -> Identity Int m n = do x <- m n y <- return (x * n) m y y = runidentity (m 4) [26..30]
A Maybe monád data Maybe a = Just a Nothing (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b (Just x) >>= f = f x Nothing >>= f = Nothing return :: a -> Maybe a return x = Just x testmaybe :: Maybe Int testmaybe = Just 3 >>= \x -> Just 4 >>= \y -> return (x + y) [27..30]
A Reader monád type Reader e a = e -> a -- (e -> a) -> (a -> (e -> b)) -> (e -> b) (>>=) :: Reader e a -> (a -> Reader e b) -> Reader e b (x >>= f) e = f (x e) e -- a -> (e -> a) return :: a -> Reader e a return x = \e -> x -- e -> e ask :: Reader e e (ask) e = e -- (e -> a) -> e -> a runreader :: Reader e a -> e -> a runreader f x = f x [28..30]
A Reader monád -- Control.Monad.Reader data Reader e a = R (e -> a) runreader :: Reader e a -> e -> a runreader (R f) x = f x instance Monad (Reader e) where return x = R (\e -> x) x >>= f = R (\e -> let x = runreader x e in runreader (f x ) e) ask :: Reader e e ask = R (\e -> e) [29..30]
A Reader monád (példa) type Identifier = String type Bindings a = Data.Map.Map Identifier a valueof :: Identifier -> Bindings a -> a valueof name binds = maybe (error "Not found") id (Data.Map.lookup name binds) bindings :: [(Identifier, a)] -> Bindings a bindings = Data.Map.fromList -- getvaluesm :: [Identifier] -> Bindings a -> [a] getvaluesm :: [Identifier] -> Reader (Bindings a) [a] getvaluesm ids = do binds <- ask return [ valueof id binds id <- ids ] getvalues :: [Identifier] -> Bindings a -> [a] getvalues ids names = runreader (getvaluesm ids) names [30..30]