简体   繁体   中英

Is GHCI monadic bind strict?

The GHC manual states this about monadic binding in GHCI:

Another important difference between the two types of binding is that the monadic bind (p <- e) is strict (it evaluates e), whereas with the let form, the expression isn't evaluated immediately:

(from here )

But I can do this in GHCI:

λ: x <- return $ error ":("
λ: :sprint x
x = _

This seems to show that the monadic bind is not strict. What am I missing?

Remember that a function being strict means f ⊥ = ⊥ . Consider:

ghci> x <- return undefined
-- no error

This means that return undefined >>= \\x -> ... is not ⊥, but that doesn't really say anything about the strictness of >>= , because of the return . This, however:

ghci> y <- undefined
*** Exception: Prelude.undefined

is the case that the manual is referring to, and it shows that bind is strict in the left argument, because undefined >>= (\\y -> ...) is ⊥. Finally,

ghci> :set -XBangPatterns
ghci> !z <- return undefined
*** Exception: Prelude.undefined

This line shows what happens if we give it a strict function as an argument, so we know that return undefined >>= f is ⊥ if f is strict . This actually follows from the monad law return x >>= f = fx , so return ⊥ >>= f = f ⊥ = ⊥

In Haskell, we separate evaluation of values from execution of computations . return (error "") is a computation that succeeds returning an undefined value, the value is not evaluated when bound. error "" :: IO a is an undefined computation, that fails immediately.

I believe this is talking about the binding, ie the pattern matching process.

let p = e in e'

is equivalent to

case e of ~p -> e'

where the pattern p has been changed into a lazy binding ~p . Essentially, let adds an implicit ~ in front of the pattern. For instance,

let [x] = [] in "hello"

evaluates to "hello" , with no runtime errors.

In do notation, a binding

do p <- e ; e'

gets transformed to something like

e >>= (\w -> case w of
   p -> e'
   _ -> fail "some message")

where w is a fresh variable. Note that p does not get a ~ here, otherwise it would always match and the _ -> fail ... case would be unreachable.

This is needed to write eg

filterRight :: [Either a b] -> [a]
filterRight xs = do
   Right x <- xs
   return x

(which is a disguised list comprehension).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM