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
mapM_
不应该懒惰吗?除了实现队列之外,复杂性不应该是O(1)
吗?
因为追加(++)
本身就是懒惰......
答案 0 :(得分:5)
如果我是邪恶的并且使用
怎么办?push' :: Int -> State (Queue Int) ()
push' 1052602983 = state $ \_ -> ((), []) -- "Muarhar!"
push' x = state $ \xs -> ((),xs++[x])
然后mapM push' [1..]
应该清楚地将状态呈现为[1052602983, 1052602984 ..]
。 pop
产生1
是错误的。但是mapM
如果没有首先评估十亿个其他数字,就不可能知道这一点。实际上将它们推向状态与此无关,push
可能完全懒惰也无关紧要:mapM
至少必须给它一个机会来检查在交付monadic程序流程之前,任何给定的数字。
答案 1 :(得分:1)
请注意do mapM_ push [1..3]; something
与:
do push 1; push 2; push 3; something
这应该解释为什么
do mapM_ push [1..]; something
永远无法执行something
。
如果你看一下州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)
您发现m >>= g
的值始终取决于g
。与Maybe
monad的定义形成对比:
instance Monad Maybe where
return x = Just x
(>>=) m g = case m of
Nothing -> Nothing
Just x -> g x
其中m >>= g
可以独立于g
,这解释了Maybe
monad如何使do-chain短路。