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

Stefan O'Rear stefanor at cox.net
Thu Aug 2 22:19:33 EDT 2007


On Thu, Aug 02, 2007 at 06:26:36PM -0700, Tim Chevalier wrote:
> On 8/2/07, Tim Chevalier <catamorphism at gmail.com> wrote:
> > I'm forwarding this to ghc-users since nobody answered on
> > haskell-cafe, and I'm still curious... (The original message is at
> > http://www.nabble.com/Lazy-in-either-argument--t4133855.html)
> >
> 
> 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
> pre-empted.
> 
> 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?

If anything I think it's a bug in the code generator/the runtime.  We
shouldn't be generating uninterruptable loops!

Option 1: Don't generate non-allocating loops.

In all functions classed as loop-breaker by the occurAnal, generate heap
checks even if there are no bytes involved.  Pro: Very simple  Con: Neil
won't be too happy ;)  Adds heap checks to pure-arithmetic loops.

Option 2: Preempt non-allocating loops.

Store somewhere the addresses of a sufficient subset of safe points.
Note that the addresses of all info tables is a sufficient subset.  On
timer interrupt, single step the code until a safepoint is reached.
Pro: low overhead and will provide most of the infrastructure I'll need
if I ever get around to trying to implement hardware heap checks in GHC.
Con: More complicated, especially if single-stepping is so high overhead
we wind up needing to implement some other scheme, like linking the
bochs core.

Stefan
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://www.haskell.org/pipermail/glasgow-haskell-users/attachments/20070802/dede934c/attachment.bin


More information about the Glasgow-haskell-users mailing list