Home > Back-end >  Data constructor not in scope despite copy-pasting exact code and importing module
Data constructor not in scope despite copy-pasting exact code and importing module

Time:01-18

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)
  • Related