为什么haskell代码没有终止 import Control.Monad.State.Lazy 类型队列a=[a] 推送::a->状态(队列a)() push x=state(\xs->((),xs++[x])) 状态(队列a)a pop=状态(\(x:xs)->(x,xs)) queueManip::状态(队列Int)Int 队列管理= 做 地图推送[1..] a

为什么haskell代码没有终止 import Control.Monad.State.Lazy 类型队列a=[a] 推送::a->状态(队列a)() push x=state(\xs->((),xs++[x])) 状态(队列a)a pop=状态(\(x:xs)->(x,xs)) queueManip::状态(队列Int)Int 队列管理= 做 地图推送[1..] a,haskell,lazy-evaluation,state-monad,Haskell,Lazy Evaluation,State Monad,注意,domapm_uuupush[1..3];某些内容与以下内容相同: 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 (Qu

注意,
domapm_uuupush[1..3];某些内容与以下内容相同:

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
这应该可以解释为什么

do push 1; push 2; push 3; something
永远不要抽出时间来执行
某件事

如果您查看状态单子的定义:

do mapM_ push [1..]; something
您可以看到
m>=g
的值始终取决于
g
。与
Maybe
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
,这解释了
可能
单子可以短路do链。

如果我是邪恶的,使用

instance Monad Maybe where
    return x = Just x
    (>>=) m g = case m of
                  Nothing -> Nothing
                  Just x  -> g x

然后
mapmpush'[1..]
应清楚地将状态呈现为
[1052602983,1052602984..]
pop
产生
1
是错误的。但是
mapM
不可能知道这一点,除非先计算出10亿个其他数字。实际上,将它们推到状态在这里是不相关的,
push
可能完全是懒惰的,这也没关系:
mapM
在提交一元程序流之前,至少要给它一个检查任何给定数字的机会。

虽然不完全相同,但你看了吗?我认为这可能是一个有效的论点,但是你仍然需要证明,一个无限的
do
链不能像Haskell中的许多其他东西一样被懒散地跳过。是的,有一些单子,其中一个do无限链不必被完全计算-例如,Maybe单子。那么,为什么参数对
状态
有效呢,有没有办法通过其他monad实现队列?所需的惰性是否可以通过其他monad实现?只需从
queueManip
中删除
mapM\uupush[1..]
并使用
runState queueManip[1..]
运行计算即可。
push' :: Int -> State (Queue Int) ()
push' 1052602983 = state $ \_ -> ((), []) -- "Muarhar!"
push' x = state $ \xs -> ((),xs++[x])