Az előző rész tartalmából...

26 

Loading....

Loading....

Loading....

Loading....

Loading....

Full text

(1)
(2)
(3)

Programozás burritokkal

(4)

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 main :: IO () main =

putStr "Provide me a word> " >> getLine >>= \s ->

if (s == reverse s)

then putStr "A palindrome." else putStr "Not a palindrome."

(5)

Programozás monádokkal – a

Monad

típusosztály

{-# LANGUAGE KindSignatures #-} -- 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 Monádtörvények: return >=> f === f f >=> return === f (f >=> g) >=> h === f >=> (g >=> h)

+

„run” függvény

[5..26]

(6)

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

}

(7)
(8)

Applicative

...?!

Prelude> :load Identity.hs

[1 of 1] Compiling Main ( Identity.hs, interpreted )

Identity.hs:6:10: Warning:

‘Identity’ is an instance of Monad but not Applicative - this will become an error in GHC 7.10, under the Applicative-Monad Proposal.

Ok, modules loaded: Main.

MindenMonadideális esetbenApplicative Functor:

class Functor (f :: * -> *) where -- Data.Functor fmap :: (a -> b) -> f a -> f b

-- Control.Applicative

class (Functor f) => Applicative (f :: * -> *) where pure :: a -> f a

(<*>) :: f (a -> b) -> f a -> f b instance (Monad m) => Functor m where

f ‘fmap‘ x = pure f <*> x

instance (Monad m) => Applicative m where

pure x = return x

af <*> ax = do { f <- af; x <- ax; return (f x) }

(9)
(10)

A

State

monád (intuíció)

type State s a = s -> (a, s)

-- (s -> (a, s)) -> (a -> (s -> (b, s))) -> (s -> (b, s)) (>>=) :: State s a -> (a -> State s b) -> State s b (x >>= f) s = (f x’) s’ where (x’, s’) = x s -- a -> (s -> (a, s)) return :: a -> State s a (return x) s = (x, s) -- s -> (s, s) get :: State s s (get) s = (s, s) -- s -> ((), s) put :: s -> State s () (put x) s = ((), x) -- (s -> (a, s)) -> s -> (a, s)) runState :: State s a -> s -> (a, s)) runState f s = f s

(11)

A

State

monád (definíció)

-- Control.Monad.State

data State s a = S (s -> (a, s)) runState :: State s a -> s -> (a, s) runState (S f) x = f x

instance Monad (State s) where return x = S (\s -> (x,s)) x >>= f = S (\s -> let (x’, s’) = runState x s in runState (f x’) s’) get :: State s s get = S (\s -> (s, s)) put :: s -> State s () put x = S (\_ -> ((), x)) [11..26]

(12)

A

State

monád (példa)

data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show

numberTree :: (Eq a) => Tree a -> Tree Int numberTree t = fst (runState (numberTreeM t) [])

numberTreeM :: (Eq a) => Tree a -> State [a] (Tree Int)

numberTreeM Leaf = return Leaf

numberTreeM (Node x lt rt) = do table <- get

let (table’, pos) = case (Data.List.findIndex (== x) table) of Just i -> (table, i)

_ -> (table ++ [x], length table) put table’

lt’ <- numberTreeM lt rt’ <- numberTreeM rt return (Node pos lt’ rt’)

(13)

A

Writer

monád (egyszer ˝usített)

-- Control.Monad.Writer data Writer w a = W (a, w)

runWriter :: (Monoid w) => Writer w a -> (a, w) runWriter (W (x, w)) = (x, w)

instance (Monoid w) => Monad (Writer w) where return x = W (x, mempty)

x >>= f = W (let (x’, w) = runWriter x in let (x’’, w’) = runWriter (f x’) in (x’’, w <> w’))

tell :: (Monoid w) => w -> Writer w () tell x = W ((), x)

censor :: (Monoid w) => (w -> w) -> Writer w a -> Writer w a censor f (W (x, w)) = W (x, f w)

(14)

A

Writer

monád (

Monoid

)

-- Data.Monoid

class Monoid (a :: *) where

mempty :: a mappend :: a -> a -> a (<>) :: (Monoid a) => a -> a -> a -- GHC 7.6+ (<>) = mappend Monoidtörvények: mempty <> x === x x <> mempty === x x <> (y <> z) === (x <> y) <> z mconcat === foldr (<>) mempty Például:

instance Monoid [a] where

mempty = []

mappend = (++) -- data Sum a = Sum a

instance (Num a) => Monoid (Sum a) where

mempty = Sum 0

(Sum x) ‘mappend‘ (Sum y) = Sum (x + y)

(15)

A

Writer

monád (példa)

gcdWithLog :: Int -> Int -> (Int, [String])

gcdWithLog x y = runWriter (censor reverse (gcdWithLogM x y)) gcdWithLogM :: Int -> Int -> Writer [String] Int

gcdWithLogM x y | y == 0 = do tell ["Finished with " ++ show x] return x

gcdWithLogM x y = do

result <- gcdWithLogM y (x ‘mod‘ y)

let msg = show x ++ " mod " ++ show y ++ " = " ++ show (x ‘mod‘ y) tell [msg]

return result

(16)
(17)

Motiváció – Monádok kombinációja

countEntries :: FilePath -> K () countEntries path = f path 0 where

f p n = do

deepestReached <- get

when (deepestReached < n) (put n)

c <- liftIO (System.Directory.getDirectoryContents p) let contents = filter (‘notElem‘ [".", ".."]) c tell [(p, length contents)]

forM_ contents (\name -> do let newName = p ++ "/" ++ name

isDir <- liftIO (System.Directory.doesDirectoryExist newName) maxDepth <- ask

when (isDir && (n < maxDepth)) (f newName (n + 1))) type S = Int

type C = Int

type K = ReaderT C (StateT S (WriterT [(FilePath,Int)] IO)) runStack :: K a -> Int -> IO ((a,S),[(FilePath,Int)]) runStack k max = runWriterT (runStateT (runReaderT k c) s)

where (s, c) = (0, max)

(18)

Monádok rétegelése (stacking)

(19)

Részletek – A

MonadTrans

és

MonadIO

osztályok

-- Control.Monad.Trans

class MonadTrans (t :: (* -> *) -> * -> *) where lift :: Monad m => m a -> t m a

Transzformátortörvények:

lift . return === return

lift (x >>= f) === lift x >>= (lift . f)

AzIOesetén ellenben:

-- Control.Monad.IO.Class

class Monad m => MonadIO (m :: * -> *) where liftIO :: IO a -> m a

instance MonadIO IO where liftIO m = m

Adaptált törvények:

liftIO . return === return

liftIO (x >>= f) === liftIO x >>= (liftIO . f)

(20)

A

ReaderT

transzformátor (egyszer ˝usített)

{-# LANGUAGE KindSignatures, TypeFamilies, FlexibleContexts #-} class (Monad m) => MonadReader (m :: * -> *) where

type EnvType m -- "associated type (synonym)" ask :: m (EnvType m)

data ReaderT e m a = RT (e -> m a) runReaderT :: ReaderT e m a -> e -> m a runReaderT (RT t) e = t e

type Reader e = ReaderT e Identity runReader :: Reader e a -> e -> a

runReader m x = runIdentity (runReaderT m x) instance (Monad m) => Monad (ReaderT e m) where

return x = lift (return x)

x >>= f = RT (\e -> do x’ <- runReaderT x e runReaderT (f x’) e)

(21)

A

ReaderT

transzformátor (egyszer ˝usített, folytatás)

instance MonadTrans (ReaderT e) where lift m = RT (\e -> m)

instance (Monad m) => MonadReader (ReaderT e m) where type EnvType (ReaderT e m) = e

-- ask :: (ReaderT e m) e ask = RT (\e -> return e)

instance (MonadState m) => MonadState (ReaderT e m) where type StateType (ReaderT e m) = StateType m

-- get :: m (StateType m)

get = lift get

-- put :: (StateType m) -> m () put s = lift (put s)

instance (MonadWriter m) => MonadWriter (ReaderT e m) where type WriterType (ReaderT e m) = WriterType m

-- tell :: (WriterType m) -> m ()

tell w = lift (tell w)

-- censor :: (WriterType m -> WriterType m) -> m a -> m a censor f m = RT (\e -> do let m’ = runReaderT m e

censor f m’)

instance (MonadIO m) => MonadIO (ReaderT e m) where liftIO m = lift (liftIO m) [21..26]

(22)

A

StateT

transzformátor (egyszer ˝usített)

class (Monad m) => MonadState m where type StateType m

get :: m (StateType m) put :: (StateType m) -> m ()

data StateT s m a = ST (s -> m (a, s)) runStateT :: StateT s m a -> s -> m (a, s) runStateT (ST t) s = t s

type State s = StateT s Identity runState :: State s a -> s -> (a, s) runState m x = runIdentity (runStateT m x) instance (Monad m) => Monad (StateT s m) where

return x = ST (\s -> return (x, s))

x >>= f = ST (\s -> do (x’, s’) <- runStateT x s runStateT (f x’) s’)

(23)

A

StateT

transzformátor (egyszer ˝usített, folytatás)

instance MonadTrans (StateT s) where lift m = ST (\s -> do x <- m

return (x, s))

instance (Monad m) => MonadState (StateT s m) where type StateType (StateT s m) = s

get = ST (\s -> return (s,s)) put s = ST (\_ -> return ((),s))

instance (MonadReader m) => MonadReader (StateT s m) where type EnvType (StateT s m) = EnvType m

ask = lift ask

instance (MonadWriter m) => MonadWriter (StateT s m) where type WriterType (StateT s m) = WriterType m

tell w = lift (tell w)

censor f m = ST (\s -> do let m’ = runStateT m s censor f m’)

instance (MonadIO m) => MonadIO (StateT s m) where liftIO m = lift (liftIO m)

(24)

A

WriterT

transzformátor (egyszer ˝usített)

class (Monoid (WriterType m), Monad m) => MonadWriter m where type WriterType m

tell :: (WriterType m) -> m ()

censor :: (WriterType m -> WriterType m) -> m a -> m a data WriterT w m a = WT (m (a,w))

runWriterT :: WriterT w m a -> m (a, w) runWriterT (WT m) = m

type Writer a = WriterT a Identity runWriter :: Writer w a -> (a, w) runWriter m = runIdentity (runWriterT m)

instance (Monoid w, Monad m) => Monad (WriterT w m) where return x = WT (return (x, mempty))

x >>= f = WT (do (x’, w) <- runWriterT x (x’’, w’) <- runWriterT (f x’) return (x’’, w <> w’))

(25)

A

WriterT

transzformátor (egyszer ˝usített, folytatás)

instance (Monoid w) => MonadTrans (WriterT w) where lift m = WT (do x <- m

return (x, mempty))

instance (Monoid w, MonadState m) => MonadState (WriterT w m) where type StateType (WriterT w m) = StateType m

get = lift get

put s = lift (put s)

instance (Monoid w, MonadReader m) => MonadReader (WriterT w m) where type EnvType (WriterT w m) = EnvType m

ask = lift ask

instance (Monoid w, Monad m) => MonadWriter (WriterT w m) where type WriterType (WriterT w m) = w

tell w = WT (return ((), w))

censor f m = WT (do (x, w) <- runWriterT m return (x, f w))

instance (Monoid w, MonadIO m) => MonadIO (WriterT w m) where liftIO m = lift (liftIO m)

(26)

A monádrétegek sorrendje (példa)

stack ::

(MonadState Int m, MonadWriter [String] m, MonadError String m) => m ()

stack = do r <- get

tell ["Hello!"] throwError "Error!"

tell ["Value: " ++ show r] put (r + 1)

type A = ErrorT String (WriterT [String] (State Int)) type B = StateT Int (WriterT [String] (Either String)) stackA :: A ()

stackA = stack stackB :: B () stackB = stack

runA = runState (runWriterT (runErrorT stackA)) 0 runB = runWriterT (runStateT stackB 0)

Figure

Updating...

References

Updating...

Related subjects :