I'm trying to run one of the most simple examples from the Haskell online book where you implement a stateful function modeling a stack of numbers. The code from the example I'm using is (http://learnyouahaskell.com/for-a-few-monads-more#state):
import Control.Monad.State
type Stack = [Int]
pop :: State Stack Int
pop = State $ \(x:xs) -> (x,xs)
push :: Int -> State Stack ()
push a = State $ \xs -> ((),a:xs)
Yet when trying to load it in Prelude I get:
state.hs:6:7: error:
Data constructor not in scope:
State :: ([a0] -> (a0, [a0])) -> State Stack Int
|
6 | pop = State $ \(x:xs) -> (x,xs)
| ^^^^^
state.hs:9:10: error:
Data constructor not in scope:
State :: ([Int] -> ((), [Int])) -> State Stack ()
|
9 | push a = State $ \xs -> ((),a:xs)
| ^^^^^
Failed, no modules loaded.
What am I missing??? Is this example somehow wrong?
I was just expecting to simply load the module with no errors. No clue what is wrong.
CodePudding user response:
Somewhat surprisingly, the Control.Monad.State
module does not contain a data constructor called State
. That would be the case if it simply defined
newtype State' s a = State { runState :: s -> (a,s) }
– which it used to do in version 1 of the mtl
library, but doesn't anymore. Since version 2.0, the module only exports a type synonym called State
, which is actually re-exported from Control.Monad.Trans.State
and is implemented thus:
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
type State s = StateT s Identity
The Identity
monad makes this behave so that m (a,s)
is isomorphic to simply (a,s)
by itself, so in the end StateT s Identity a
is indeed isomorphic to State' s a
. It is however more general: StateT
is a monad transformer that can also be stacked on top of other monadic actions, such as IO
.
So you can't use a State
value constructor, but you can use state
which behaves exactly as State
behaved in mtl-1.1
. (Except you can't pattern match on it, but you can still use runState
.)
pop :: State Stack Int
pop = state $ \(x:xs) -> (x,xs)
push :: Int -> State Stack ()
push a = state $ \xs -> ((),a:xs)