Why the Haskell sequence function can't be lazy or why recursive monadic functions can't be lazy

前端 未结 3 1863
青春惊慌失措
青春惊慌失措 2020-12-18 22:23

With the question Listing all the contents of a directory by breadth-first order results in low efficiencyI learned that the low efficiency is due to a strange behavior of t

3条回答
  •  感情败类
    2020-12-18 22:57

    The problem isn't the definition of sequence, it's the operation of the underlying monad. In particular, it's the strictness of the monad's >>= operation that determines the strictness of sequence.

    For a sufficiently lazy monad, it's entirely possible to run sequence on an infinite list and consume the result incrementally. Consider:

    Prelude>  :m + Control.Monad.Identity
    Prelude Control.Monad.Identity> runIdentity (sequence $ map return [1..] :: Identity [Int])
    

    and the list will be printed (consumed) incrementally as desired.

    It may be enlightening to try this with Control.Monad.State.Strict and Control.Monad.State.Lazy:

    -- will print the list
    Prelude Control.Monad.State.Lazy> evalState (sequence $ map return [1..] :: State () [Int]) ()
    -- loops
    Prelude Control.Monad.State.Strict> evalState (sequence $ map return [1..] :: State () [Int]) ()
    

    In the IO monad, >>= is by definition strict, since this strictness is exactly the property necessary to enable reasoning about effect sequencing. I think @jberryman's answer is a good demonstration of what is meant by a "strict >>=". For IO and other monads with a strict >>=, each expression in the list must be evaluated before sequence can return. With an infinite list of expressions, this isn't possible.

提交回复
热议问题