| I've got an inner loop that I think I can see is strict in the Int
| argument being passed around, but that GHC 6.6.1 isn't unboxing. In the
| following example both functions take a GHC.Base.Int, which I think
| should be an Int#.

OK this is an interesting one. Here's the smallest program that demonstrates 
the problem.

foreign import ccall unsafe "stdio.h getchar" getchar :: IO CInt

f56 :: State# RealWorld -> Int -> Int
f56 s v2 = case (unIO getchar s) of
           (# s' , v6  #) ->
              case v2 of I# _ -> f56 s' v2

GHC says this is lazy in v2, which it obviously isn't.  Why?  Because there's a 
special hack (introduced after an earlier bug report) in the strictness 
analyser to account for the fact that a ccall might exit the program.  Suppose 
instead of calling 'getchar' we called 'exit'!  Then f56 is not strict in v2 
any more.

Here was a larger program that demonstrated the problem:

        do { let len = <expensive> ;
           ; when (...) (exitWith ExitSuccess)
           ; print len }

Suppose exitWith doesn't exit; it loops or returns. Then 'len' is sure to be 
evaluated, and GHC will evaluate it before the 'when'.

The hack is in the demand analyser, to make it believe that any I/O operation 
(including getchar!) might exit instead of returning.


OK, so that's the reason you aren't getting proper strictness in your inner 
loop.  What to do about it? It would be easy to revert to the non-hack 
situation, in which case 'len' might well be evaluated in the program above, 
even in the program above.  To make the program sufficiently lazy you could 
write

        do { let len = <expensive> ;
           ; when (...) (exitWith ExitSuccess)
           ; lazy (print len) }

Here 'lazy' is a (documented) function that makes its argument appear to be 
evaluated lazily, so far as the demand analyser is concerned.  But this is 
horribly non-compositional.  ANYWHERE you say
        do { a; b; c }
and b might exit, then you should really say 'lazy c'.


One could imagine an analysis for "definitely does not exit".  But it only 
really makes sense for IO-ish things.

In short, it's hard to see a beautiful solution.  Does anyone else have ideas?

Simon
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

Reply via email to