Background
This question arises from a challenge Brent Yorgey posed at OPLSS: write a function f :: (Int -> Int) -> Bool
that distinguishes f undefined
from f (\x -> undefined)
. All of our answers either used seq
or something like bang patterns that desugar into seq
. For example:
f :: (Int -> Int) -> Bool
f g = g `seq` True
*Main> f undefined
*** Exception: Prelude.undefined
*Main> f (\x -> undefined)
True
The GHC commentary on seq
says that
e1 `seq` e2
used to desugar into
case e1 of { _ -> e2 }
so I tried desugaring manually. It didn't work:
f' g = case g of { _ -> True }
*Main> f' undefined
True
*Main> f' (\x -> undefined)
True
Question
Does this behavior depend on the more complex seq
described at the end of the commentary, and if so, how does it work? Could such an f
be written without these primitives?
x `seq` e2 ==> case seq# x RW of (# x, _ #) -> e2 -- Note shadowing!
e1 `seq` e2 ==> case seq# x RW of (# _, _ #) -> e2