Reputation: 31
import Control.Monad.State.Lazy
type Queue a = [a]
push :: a -> State (Queue a) ()
push x = state (\xs -> ((),xs++[x]))
pop :: State (Queue a) a
pop = state (\(x:xs) -> (x,xs))
queueManip :: State (Queue Int) Int
queueManip =
do
mapM_ push [1..]
a <- pop
return a
main :: IO()
main = do
let (a,_) = runState queueManip []
print a
Shouldn't the mapM_
be lazy ? Besides for implementing a queue shouldn't the complexity be O(1)
?
Because the append (++)
itself is lazy ...
Upvotes: 3
Views: 190
Reputation: 52029
Note that do mapM_ push [1..3]; something
is the same as:
do push 1; push 2; push 3; something
so that should explain why
do mapM_ push [1..]; something
never gets around to executing something
.
If you look at the definition of the State monad:
type State s a = s -> (a, s)
instance Monad (State s) where
return a = \s -> (a,s)
m >>= g = wpAB
where
wpAB = \s1 -> let (v2, s2) = m s1
(v3, s3) = g v2 s2
in (v3, s3)
-- (newtypes and such have been removed to declutter the code)
you see that the value of m >>= g
always depends on g
. Contrast that with the definition of Maybe
monad:
instance Monad Maybe where
return x = Just x
(>>=) m g = case m of
Nothing -> Nothing
Just x -> g x
where m >>= g
can be independent of g
which explains how the Maybe
monad can short-circuit a do-chain.
Upvotes: 1
Reputation: 120711
What if I'm evil and use
push' :: Int -> State (Queue Int) ()
push' 1052602983 = state $ \_ -> ((), []) -- "Muarhar!"
push' x = state $ \xs -> ((),xs++[x])
Then mapM push' [1..]
should clearly render the state as [1052602983, 1052602984 ..]
. It would be wrong for pop
to yield 1
. But mapM
can't possibly know this, without first evaluating a billion other numbers. Actually pushing them to the state is irrelevant here, and it also doesn't matter that push
could be completely lazy: mapM
at least has to give it a chance to check any given number, before handing on the monadic program flow.
Upvotes: 5