【问题标题】:Why does this haskell code not terminate为什么这个haskell代码不会终止
【发布时间】:2015-07-09 04:32:04
【问题描述】:
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)吗?

因为附加 (++) 本身是惰性的...

【问题讨论】:

标签: haskell lazy-evaluation state-monad


【解决方案1】:

如果我是邪恶的并使用怎么办

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 至少必须给它一个 机会 来检查任何给定的数字,在处理一元程序流程之前。

【讨论】:

    【解决方案2】:

    注意do mapM_ push [1..3]; something 等同于:

    do push 1; push 2; push 3; something
    

    所以这应该解释为什么

    do mapM_ push [1..]; something
    

    从不执行something

    如果你看一下 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)
    

    您会看到m &gt;&gt;= g 的值始终取决于g。对比Maybemonad的定义:

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

    其中m &gt;&gt;= g 可以独立于g,这解释了Maybe monad 如何使do-chain 短路。

    【讨论】:

    • 我认为这可能是一个有效的论点,但你仍然需要证明一个无限的 do 链不能像 Haskell 中的许多其他东西一样被懒惰地跳过。
    • 是的 - 有些单子不需要完全评估 do 无限链 - 例如Maybe monad。
    • 那么,为什么该参数对State 有效呢?
    • 好吧,话虽这么说,有没有办法可以通过其他一些单子来实现队列?是否可以通过其他一些 monad 强制执行所需的惰性?
    • 只需从queueManip 中删除mapM_ push [1..] 并使用runState queueManip [1..] 运行您的计算。
    猜你喜欢
    • 2015-01-09
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 2014-01-08
    • 1970-01-01
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    相关资源
    最近更新 更多