Why are some styles prefixed with "Monad"?

After reading some code, I sometimes encounter classes with the prefix Monad

, examples of which include MonadState

, MonadIO

, MonadReader

and etc.

What is their purpose?

Taking MonadState

as an example, I know that

  • State

    allows stateless state
  • StateT

    allows other monads to be used, for example IO

    to "combine" the functionality of both

But MonadState

lets exactly?

I don't need another group of identically named types / types, can someone explain?

+3


source to share


2 answers


State

, StateT

and other types such as these are related to transformers

, while the class MonadState

and other classes such as it comes from mtl

. Note that the former are types and the latter are types.

Types from transformers

are instances of Monad

and MonadTrans

. You can work with them directly, but there are a few annoyances:

  • If you have multiple stacks with multiple layers, you have to sprinkle your code with a lot of calls lift

    to access the functions of each layer.

  • Sometimes two different types provide the same "interface". For example, both RWST

    and ReaderT

    offer reading features such as ask

    . When writing a function, it is annoying to have to do one from the other, reducing generality.



Scripting Monad*

from mtl

makes these problems easier:

  • They have "end-to-end" instances that eliminate many of the calls lift

    (or rather, handle them automatically). For example StateT

    is an instance MonadState

    , but ReaderT

    over is StateT

    also an instance MonadState

    , so you can use directly get

    .

    import Control.Monad
    import Control.Monad.Reader
    import Control.Monad.State
    
    -- put the environment in the state
    bar :: ReaderT Int (State Int) ()
    bar = ask >>= lift . put -- we use lift here
    
    barMTL :: ReaderT Int (State Int) ()
    -- This ONLY works if we have imported the 
    -- required instances from mtl.
    -- The MonadState instance for ReaderT, in particular.
    barMTL = ask >>= put -- the put is auto-lifted
    
          

  • You can put a constraint Monad*

    in your functions and work with the interface Monad*

    "instead of immediately executing a specific implementation of the monad. Thus, your functions become more general, and the choice of the exact" implementation "is delayed until the last moment.

    import Control.Monad
    import Control.Monad.State
    import Control.Monad.RWS
    
    -- Dumb function that increments the state.
    -- Doesn't commit to a specific implementation of the monad.
    baz :: MonadState Int m => m ()
    baz = modify succ
    
    main :: IO ()
    main = do
        -- run as State
        print $ runState baz 0 
        -- run as RWS
        print $ runRWS (baz >> tell ()) () 0
    
          

+7


source


MonadState

is not a monad but a subclass Monad

. State

is a monad (and also a MonadState

). Subclass subclass MonadState

used to create features such as get

, put

for any monads, which has the concept of custom "state".



+2


source







All Articles