How does seq force functions?

Viewed 3153

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
2 Answers
Related