Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use MultiParamTypeClasses in a MonadState

Tags:

haskell

class Monad m => MonadState s m | m -> s where
    -- | Return the state from the internals of the monad.
    get :: m s
    get = state (\s -> (s, s))

    -- | Replace the state inside the monad.
    put :: s -> m ()
    put s = state (\_ -> ((), s))

    -- | Embed a simple state action into the monad.
    state :: (s -> (a, s)) -> m a
    state f = do
      s <- get
      let ~(a, s') = f s
      put s'
      return a

instance MonadState s m => MonadState s (MaybeT m) where...

Why does a instance of MonadState need a state and a monad, why not create a single parameter State class?

like image 279
Gert Cuykens Avatar asked Sep 02 '12 16:09

Gert Cuykens


1 Answers

Let me try and answer Gert's question in the comments, because it's a pretty different question.

The question is, why can we not just write

class State s where
   get :: s
   put :: s -> ()

Well, we could write this. But now the question is, what can we do with it? And the hard part is, if we have some code with put x and then later get, how do we link the get to the put so that the same value is returned as the one put in?

And the problem is, with just the types () and s, there is no way to link one to the other. You can try implementing it in various ways, but it won't work. There's just no way to carry the data from the put to the get (maybe someone can explain this better, but the best way to understand is to try writing it).

A Monad is not necessarily the only way to make operations linkable, but it is a way, because it has the >> operator to link two statements together:

(>>) :: m a -> m b -> m b

so we can write

(put x) >> get

EDIT: Here is an example using the StateT instance defined in the package

foo :: StateT Int IO ()
foo = do
    put 3
    x <- get
    lift $ print x

main = evalStateT foo 0
like image 194
Owen Avatar answered Sep 28 '22 13:09

Owen