Ivan Jovanovic ivan.jovanovic@gmail.com
HaskellerZ meetup - 29.05.2014
class Monad m where
-- | Inject a value into the monadic type.
return :: a -> m a
-- | Sequentially compose two actions, passing any value produced
-- by the first as an argument to the second.
(>>=) :: m a -> (a -> m b) -> m b
return a >>= k == k a
m >>= return == m
m >>= (\x -> k x >>= h) == (m >>= k) >>= h
instance (Error e) => Monad (Either e) where
return = Right
Left l >>= _ = Left l
Right r >>= k = k r
instance Monad (State s) where
return a = State $ \s -> (a, s)
m >>= k = State $ \s -> do
(a, s') <- (runState m) s
runState (k a) s'
instance Monad (Reader r) where
return = lift . return
m >>= k = Reader $ \ r -> do
a <- (runReader m) r
runReader (k a) r
instance (Monoid w) => Monad (Writer w) where
return a = Writer (a, mempty)
m >>= k = Writer $ do
(a, w) <- runWriter m
(b, w') <- runWriter (k a)
return (b, w `mappend` w')
instance Monad (StateWithError s e) where
return a = StateWithError $ \s -> Right (a, s)
(StateWithError p) >>= k =
StateWithError $ \s0 ->
case p s0 of
Right (val, s1) ->
let (StateWithError q) = k val
in q s1
Left e -> Left e
* transformers is a Haskell 98 package containing
* base functors (Data.Functor.Constant and Data.Functor.Identity),
* operations on functors (Data.Functor.Compose and Data.Functor.Product),
* transformer classes (Control.Monad.Trans.Class and
Control.Monad.IO.Class) and
* concrete monad transformers with code to lift operators
(Control.Monad.Trans.*).
The package can be used on its own (see the Control.Monad.Trans.Class
documentation for examples), or with packages adding type classes.
* mtl-2 (the current monads-fd) depends on transformers and adds type
classes using functional dependencies. It has the same modules as
mtl-1 and usage is very close, except for the differences listed below.
-- | Counts number of entries in each folder as it traverses the folder tree.
-- Stores the results in a list.
countEntries :: FilePath -> IO [(FilePath, Int)]
countEntries path = do
contents <- listDirectory path
rest <- forM contents $ \name -> do
let newName = path </> name
isDir <- doesDirectoryExist newName
if isDir
then countEntries newName
else return []
return $ (path, length contents) : concat rest
-- | Traverses the folder tree and counts number of entries.
-- Writes results into a writer log along the way (tell).
countEntries :: FilePath -> WriterT [(FilePath, Int)] IO ()
countEntries path = do
contents <- liftIO . listDirectory $ path
-- store the value in the log
tell [(path, length contents)]
forM_ contents $ \name -> do
let newName = path </> name
isDir <- liftIO . doesDirectoryExist $ newName
when isDir $ countEntries newName
-- ---------------------------------------------------------------------------
-- | A writer monad parameterized by:
--
-- * @w@ - the output to accumulate.
--
-- * @m@ - The inner monad.
--
-- The 'return' function produces the output 'mempty', while @>>=@
-- combines the outputs of the subcomputations using 'mappend'.
newtype WriterT w m a = WriterT { runWriterT :: m (a, w) }
instance (Monoid w, Monad m) => Monad (WriterT w m) where
return a = writer (a, mempty)
m >>= k = WriterT $ do
(a, w) <- runWriterT m
(b, w') <- runWriterT (k a)
return (b, w `mappend` w')
instance (Monoid w) => MonadTrans (WriterT w) where
lift m = WriterT $ do
a <- m
return (a, mempty)
class (Monad m) => MonadIO m where
-- | Lift a computation from the 'IO' monad.
liftIO :: IO a -> m a
instance MonadIO IO where
liftIO = id
-- | Underlying monad has to implement the MonadIO instance
instance (Monoid w, MonadIO m) => MonadIO (WriterT w m) where
liftIO = lift . liftIO
type Writer w = WriterT w Identity
Monad
IO
Control.Monad.IO.Class
Trans
Control.Monad.Trans.Class
Control.Monad.Trans.Cont
Control.Monad.Trans.Error
Control.Monad.Trans.Except
Control.Monad.Trans.Identity
Control.Monad.Trans.List
Control.Monad.Trans.Maybe
Control.Monad.Trans.RWS
Control.Monad.Trans.RWS.Lazy
Control.Monad.Trans.RWS.Strict
Control.Monad.Trans.Reader
Control.Monad.Trans.State
Control.Monad.Trans.State.Lazy
Control.Monad.Trans.State.Strict
Control.Monad.Trans.Writer
Control.Monad.Trans.Writer.Lazy
Control.Monad.Trans.Writer.Strict
Data
Functor
Identity
-- | Counter monad stack.
type Counter a = ReaderT CounterConfig (StateT CounterState (WriterT CounterLog IO)) a
-- | Runner of the monad with provided configuration.
runCounter :: Counter a -> CounterConfig -> IO ((a, CounterState), CounterLog)
runCounter m config =
let initialState = CounterState 0
in
runWriterT $ runStateT (runReaderT m config) initialState
-- | Lift writer operation.
counterTell :: CounterLog -> Counter ()
counterTell = lift . lift . tell
-- | Lift state get operation.
counterGet :: Counter CounterState
counterGet = lift get
-- | lift state put operation.
counterPut :: CounterState -> Counter ()
counterPut = lift . put
Control
Monad
Control.Monad.Cont
Control.Monad.Cont.Class
Control.Monad.Error
Control.Monad.Error.Class
Control.Monad.Identity
Control.Monad.List
Control.Monad.RWS
Control.Monad.RWS.Class
Control.Monad.RWS.Lazy
Control.Monad.RWS.Strict
Control.Monad.Reader
Control.Monad.Reader.Class
Control.Monad.State
Control.Monad.State.Class
Control.Monad.State.Lazy
Control.Monad.State.Strict
Control.Monad.Trans
Control.Monad.Writer
Control.Monad.Writer.Class
Control.Monad.Writer.Lazy
Control.Monad.Writer.Strict
class (Monoid w, Monad m) => MonadWriter w m | m -> w where
-- | @'tell' w@ is an action that produces the output @w@.
tell :: w -> m ()
instance MonadWriter w m => MonadWriter w (ReaderT r m) where
tell = lift . tell
instance (Monoid w, Monad m) => MonadWriter w (WriterT w m) where
tell = id
instance MonadWriter w m => MonadWriter w (StateT s m) where
tell = lift . tell
instance MonadWriter w m => MonadWriter w (ReaderT r m) where
tell = lift . tell
instance (Error e, MonadWriter w m) => MonadWriter w (ErrorT e m) where
tell = lift . tell
instance MonadWriter w m => MonadWriter w (ExceptT e m) where
tell = lift . tell
instance MonadWriter w m => MonadWriter w (IdentityT m) where
tell = lift . tell
instance MonadWriter w m => MonadWriter w (MaybeT m) where
tell = lift . tell
-- | Our monad stack.
newtype Counter a = Counter {
runCounter :: ReaderT CounterConfig (StateT CounterState (WriterT CounterLog IO)) a
} deriving ( Monad, MonadIO, MonadReader CounterConfig
, MonadState CounterState, MonadWriter CounterLog)
-- | Traverses the folder tree and counts number of entries.
-- Writes results into a writer log along the way.
countEntries :: FilePath -> Counter ()
countEntries path = do
contents <- liftIO . listDirectory $ path
-- gets the configuration
cfg <- ask
-- gets the current state
st <- get
-- records the log
tell [(path, length contents)]
forM_ contents $ \name -> do
let newPath = path </> name
depth = currentDepth st
isDir <- liftIO . doesDirectoryExist $ newPath
when (isDir && depth < maxDepth cfg) $ do
-- updates the state
put st {currentDepth = depth + 1}
countEntries newPath
-- | The X monad, 'ReaderT' and 'StateT' transformers over 'IO'
-- encapsulating the window manager configuration and state,
-- respectively.
--
-- Dynamic components may be retrieved with 'get', static components
-- with 'ask'. With newtype deriving we get readers and state monads
-- instantiated on 'XConf' and 'XState' automatically.
--
newtype X a = X (ReaderT XConf (StateT XState IO) a)
deriving (Functor, Monad, MonadIO, MonadState XState, MonadReader XConf, Typeable)
instance Monad [] where
return x = [x]
[] >>= _ = []
(x:xs) >>= k = k x ++ (xs >>= k)
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
instance MonadPlus [] where
mzero = []
mplus u v = u ++ v
-- | Definition of the monadic data structure
data Plus a
-- basic structure
= Unit a
| forall b. Bind (Plus b) (b -> Plus a)
-- effects
| Zero
| Plus (Plus a) (Plus a)
instance Monad Plus where
return = Unit
(>>=) = Bind
instance MonadPlus Plus where
mzero = Zero
mplus = Plus
-- evaluator of the monadic data structure
run_list :: Plus a -> [a]
run_list (Unit a) = [a]
run_list m@Zero = run_list (Bind m Unit)
run list m@(Plus _ _) = run_list (Bind m Unit)
run_list (Bind (Unit v) k) = run_list (k v)
run_list (Bind (Bind m k) g) = run_list (Bind m cont)
where cont v = Bind (k v) g
run_list (Bind Zero _) = [ ]
run_list (Bind (Plus m n) k) = ms ++ ns
where ms = run_list (Bind m k)
ns = run_list (Bind n k)
data Unimo r a
= Unit a
| Effect (r (Unimo r) a)
| forall b. Bind (Unimo r b) (b -> Unimo r a)
instance Monad (Unimo r) where
return = Unit
(>>=) = Bind
type BindOp r a v = forall b.
r (Unimo r) b -> (b -> Unimo r a) -> v
type Observer r a v =
(a -> v) -> BindOp r a v -> Unimo r a -> v
-- | Monad observer function
observe_monad :: Observer r a v
observe_monad unit_op bind_op = eval where
eval (Unit v) = unit_op v
eval (Effect e) = e `bind_op` Unit
eval (Bind (Effect e) k) = e `bind_op` k
eval (Bind (Unit v) k) = eval (k v)
eval (Bind (Bind m k) g) = eval (Bind m cont)
where cont v = Bind (k v) g
-- | Expressing just effect part of the monad
data PlusE m a
= Zero
| Plus (m a) (m a)
-- | Full monadic value.
type Plus = Unimo PlusE
run_list :: Plus a -> [a]
run_list = observe monad unit_op bind_op where
unit_op v = [v]
bind_op Zero = [ ]
bind_op (Plus m n) k =
let ms = run_list (Bind m k)
ns = run_list (Bind n k)
in ms ++ ns
Space, Right Arrow or swipe left to move to next slide, click help below for more details