Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Data constructor not in scope despite copy-pasting exact code and importing module

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?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I was just expecting to simply load the module with no errors. No clue what is wrong.

>Solution :

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)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading