Adding type signature changes semantics (was [Haskell-cafe] Lazy in either argument?)

Tim Chevalier catamorphism at
Thu Aug 2 21:26:36 EDT 2007

On 8/2/07, Tim Chevalier <catamorphism at> wrote:
> I'm forwarding this to ghc-users since nobody answered on
> haskell-cafe, and I'm still curious... (The original message is at

Replying to myself again, I figured out later that what's really going
on in this example is that when you write:
f = f
(with no type signature) it desugars to:
f = \@a -> let f' = f' in f'
whereas if you write:
f :: Bool
f = f
the code is left more or less as is (if you're compiling with -Onot).
Then the let-body in the unannotated version gets compiled to a loop
that doesn't allocate, whereas (and I don't quite follow why) the
definition in the annotated version gets compiled to a loop that
allocates a new closure on each iteration. Thus, in the example with
two threads, the second version will be pre-empted to run the other
thread that does terminate, whereas the first version will never be

This makes sense at least if you consider the desugaring of
polymorphic definitions separately from the semantics of threads...
it's only when they interact that something strange happens. Maybe
it's an extreme corner case, but it still seems weird to me that
adding or removing a type signature should change the semantics of
code like this. It seems to me like the problem is that that the
transformation from (f = f) to (f = let f' = f' in f') isn't valid in
the presence of threads, since in a multithreaded situation the two
are observably different... but is that a bug in the desugarer, or a
bug in GHC's concurrency semantics?


Tim Chevalier * chevalier at * Often in error, never in doubt

More information about the Glasgow-haskell-users mailing list