The state monad and learnyouahaskell.com

The accepted answer already mentions to use the state function from Control.Monad.State rather than the State type. However, if you simply try the accepted answer in ghci with the associated mtl package loaded, it will still fail:

Prelude Control.Monad.State> push a = state $ \xs -> ((), a:xs)

<interactive>:5:1: error:
    • Non type-variable argument in the constraint: MonadState [a] m
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        push :: forall a (m :: * -> *). MonadState [a] m => a -> m ()

To resolve this, there are two options here:

  1. Either specify the type signature for the function (which you should anyways).
  2. Add the FlexibleContexts compiler extension, as mentioned in the error.

We can specify the type signature:

module LearnYouAHaskell where

import Control.Monad.State as State

push :: Int -> State.State [Int] ()
push a = State.state $ \xs -> ((), a:xs)

The above compiles fine and functions as expected.

Or we can add the language extension so it can infer the function type.

{-# LANGUAGE FlexibleContexts #-}
module LearnYouAHaskell where

import Control.Monad.State as State

push a = State.state $ \xs -> ((), a:xs)

Which will also work fine.


As I mentioned in comments, you ought to use state instead of State.


The problem is that State is not standalone data type (or rather newtype), but it is the StateT transformer applied to Identity monad. Actually, it's defined as

type State s = StateT s Indentity

and because it's just type synonym, it cannot have State constructor. That's why Control.Monad.State uses state.

Tags:

Haskell

Monads