Question

As a learning exercise, I'm trying to implement a heapsort in Haskell. I figured the State monad would be the right choice to do this, since heaps rely pretty heavily on moving data around inside a single structure (and do notation would be useful). Besides, I'm looking to cement my understanding of monads in general.

The examples on the State monad in Learn You A Haskell (and a number of other tutorials), say that State is defined as:

newtype State s a = State { runState :: s -> (a,s) }

I should be passing a function of type s -> (a,s) (which may or may not be curried in other arguments) to the State value constructor. So my functions look like this:

pop :: Ord a => State (Heap a) a
pop = State pop'
pop' :: Ord a => Heap a -> (a, Heap a)
-- implementation of pop' goes here

push :: Ord a => a -> State (Heap a) ()
push item = State $ push' item
push' :: Ord a => a -> Heap a -> ((), Heap a)
-- implementation of push' goes here

This doesn't compile, with the following error:

Not in scope: data constructor `State'
Perhaps you meant `StateT' (imported from Control.Monad.State)

From reading the API docs for Control.Monad.State, it looks as though the State value constructor has been removed from the module since these tutorials were written. As a beginner, I find the documentation to be far from self-explanatory. So my question is:

  1. Am I right in believing that the State value constructor is gone?
  2. What should I be using instead?
Was it helpful?

Solution

  1. Yes, it's gone, replaced by StateT. (The State monad is now defined in terms of the StateT monad transformer.)
  2. You should be using the state function instead.

I would question whether your approach is correct, however. Instead of worrying about how State is implemented, consider using do-notation and the get and put functions.

OTHER TIPS

Here are the correct implementations of the examples shown in the book related to State Monad:

MONADIC STACK:

-- MonadicStack.hs (Learn You a Haskell for Great Good!)

import Control.Monad.State  

type Stack = [Int]

pop :: State Stack Int
-- The following line was wrong in the book:
-- pop = State $ \(x:xs) -> (x,xs)  
pop = do
 x:xs <- get
 put xs
 return x

push :: Int -> State Stack ()  
-- The following line was wrong in the book:
-- push a = State $ \xs -> ((),a:xs)
push a = do
 xs <- get
 put (a:xs)
 return ()

pop1 = runState pop [1..5]
push1 = runState (push 1) [2..5]

stackManip :: State Stack Int  
stackManip = do  
 push 3  
 a <- pop  
 pop  

stackManip1 = runState stackManip [5,8,2,1]  
stackManip2 = runState stackManip [1,2,3,4]  

stackStuff :: State Stack ()  
stackStuff = do  
 a <- pop  
 if a == 5  
  then push 5  
  else do  
   push 3  
   push 8  

stackStuff1 = runState stackStuff [9,0,2,1,0]  
stackStuff2 = runState stackStuff [5,4,3,2,1]

moreStack :: State Stack ()  
moreStack = do  
 a <- stackManip  
 if a == 100  
  then stackStuff  
  else return ()  

moreStack1 = runState moreStack [100,9,0,2,1,0]
moreStack2 = runState moreStack [9,0,2,1,0]

stackyStack :: State Stack ()  
stackyStack = do  
 stackNow <- get  
 if stackNow == [1,2,3]  
  then put [8,3,1]  
  else put [9,2,1]  

stackyStack1 = runState stackyStack [1,2,3]
stackyStack2 = runState stackyStack [10,20,30,40]

MONADIC RANDOM GENERATORS:

-- MonadicRandomGenerator.hs (Learn You a Haskell for Great Good!)

import System.Random  
import Control.Monad.State  

randomSt :: (RandomGen g, Random a) => State g a  
-- The following line was wrong in the book:
-- randomSt = State random
randomSt = do
 gen <- get
 let (value,nextGen) = random gen
 put nextGen
 return value

randomSt1 = (runState randomSt (mkStdGen 1)) :: (Int,StdGen)
randomSt2 = (runState randomSt (mkStdGen 2)) :: (Float,StdGen)

threeCoins :: State StdGen (Bool,Bool,Bool)  
threeCoins = do  
 a <- randomSt  
 b <- randomSt  
 c <- randomSt  
 return (a,b,c)  

threeCoins1 = runState threeCoins (mkStdGen 33)
threeCoins2 = runState threeCoins (mkStdGen 2)

-- rollDie and rollNDice are not explained in the book LYAHFGG. 
-- But these functions are interesting and complementary:

rollDie :: State StdGen Int
rollDie = do 
 generator <- get
 let (value, newGenerator) = randomR (1,6) generator
 put newGenerator
 return value

rollDie1 = runState rollDie (mkStdGen 1)
rollDie2 = runState rollDie (mkStdGen 2)

rollNDice :: Int -> State StdGen [Int]
rollNDice 0 = do
 return []
rollNDice n = do
 value <- rollDie
 list <- rollNDice (n-1)
 return (value:list)

rollNDice1 = runState (rollNDice 10) (mkStdGen 1)
rollNDice2 = runState (rollNDice 20) (mkStdGen 2)

I think state makes for a succinct implementation of pop, but modify is better for push since it returns unit:

import Control.Monad.State  

type Stack a = [a]

pop :: State (Stack a) a
pop = state $ \(a:as) -> (a, as)

push :: a -> State (Stack a) ()  
push a = modify (a:)

DESUGARED MONADIC STACK:

-- DesugaredMonadicStack.hs (Learn You a Haskell for Great Good!)

import Control.Monad.State  

type Stack = [Int]

pop :: State Stack Int  
pop = 
 get >>=
 \(x:xs) -> put xs >>
 return x

push :: Int -> State Stack ()
push a =
 get >>=
 \xs -> put (a:xs) >>
 return ()

pop1 = runState pop [1..5]
push1 = runState (push 1) [2..5]

stackManip :: State Stack Int  
stackManip =
 push 3 >>
 pop >>=
 \a -> pop

stackManip1 = runState stackManip [5,8,2,1]  
stackManip2 = runState stackManip [1,2,3,4]  

stackStuff :: State Stack ()  
stackStuff =
 pop >>=
 \a -> 
  if a == 5 then
   push 5
  else
   push 3 >>
   push 8

stackStuff1 = runState stackStuff [9,0,2,1,0]  
stackStuff2 = runState stackStuff [5,4,3,2,1]

moreStack :: State Stack ()  
moreStack =
 stackManip >>=
 \a ->
  if a == 100 then
   stackStuff
  else
   return ()

moreStack1 = runState moreStack [100,9,0,2,1,0]
moreStack2 = runState moreStack [9,0,2,1,0]
moreStack3 = runState moreStack [100,5,4,3,2,1]

stackyStack :: State Stack ()  
stackyStack =
 get >>=
 \stackNow ->
  if stackNow == [1,2,3] then
   put [8,3,1]
  else
   put [9,2,1]

stackyStack1 = runState stackyStack [1,2,3]
stackyStack2 = runState stackyStack [10,20,30,40] 

DESUGARED MONADIC RANDOM GENERATOR:

-- DesugaredMonadicRandomGenerator.hs (Learn You a Haskell for Great Good!)

import System.Random  
import Control.Monad.State  

randomSt :: (RandomGen g, Random a) => State g a  
randomSt =
 get >>=
 \gen -> 
  let (value,nextGen) = random gen
  in
   put nextGen >>
   return value

randomSt1 = (runState randomSt (mkStdGen 1)) :: (Int,StdGen)
randomSt2 = (runState randomSt (mkStdGen 2)) :: (Float,StdGen)

threeCoins :: State StdGen (Bool,Bool,Bool)
threeCoins =
 randomSt >>=
 \a -> randomSt >>=
 \b -> randomSt >>=
 \c -> return (a,b,c)

threeCoins1 = runState threeCoins (mkStdGen 33)
threeCoins2 = runState threeCoins (mkStdGen 2)

-- rollDie and rollNDice are not explained in the book LYAHFGG. 
-- But these functions are interesting and complementary:

rollDie :: State StdGen Int
rollDie =
 get >>=
 \generator -> 
  let (value, newGenerator) = randomR (1,6) generator
  in
   put newGenerator >>
   return value

rollDie1 = runState rollDie (mkStdGen 1)
rollDie2 = runState rollDie (mkStdGen 2)

rollNDice :: Int -> State StdGen [Int]
rollNDice 0 = return []
rollNDice n =
 rollDie >>=
 \value -> rollNDice (n-1) >>=
 \list -> return (value:list)

rollNDice1 = runState (rollNDice 10) (mkStdGen 1)
rollNDice2 = runState (rollNDice 20) (mkStdGen 2) 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top