#5775: Inconsistency in demand analysis
---------------------------------+------------------------------------------
    Reporter:  rl                |       Owner:                         
        Type:  bug               |      Status:  new                    
    Priority:  normal            |   Milestone:  7.4.2                  
   Component:  Compiler          |     Version:  7.5                    
    Keywords:                    |          Os:  Unknown/Multiple       
Architecture:  Unknown/Multiple  |     Failure:  Runtime performance bug
  Difficulty:  Unknown           |    Testcase:                         
   Blockedby:                    |    Blocking:                         
     Related:                    |  
---------------------------------+------------------------------------------

Comment(by simonpj):

 OK I understand what is happening here.  Consider this:
 {{{
 f x = do { writeMutVar v 3
          ; if x then ... else .. }
 foo xs = catch (f (head xs))
                (\_ -> readMutVar v)
 }}}
 Question: can I use call-value for `f`?  Is `f` strict in `x`?

 Well, when you call `f`, it'll certainly evalute `x` (I'm going to ignore
 the state-token bit here; it's not the point.)  But
  * if you use call-by-value, the the call `foo []` will throw an exception
 ''before'' executing the `writeMutVar`.
  * if you use cally-by-need, the call `foo []` will throw an exception
 only ''after'' executing the `writeMutVar`.
 The difference is observable.

 It's even more stark if in instead of `writeMutVar` you have `throwIO`, so
 that execution should not proceed beyond the `throwIO`.

 Tickets #148 and #1592 concerned exactly this point. The fix in #148
 (''nine'' years ago!) added a grotesque HACK in the demand analyser,
 commented thus:
 {{{
         -- There's a hack here for I/O operations.  Consider
         --      case foo x s of { (# s, r #) -> y }
         -- Is this strict in 'y'.  Normally yes, but what if 'foo' is an
 I/O
         -- operation that simply terminates the program (not in an
 erroneous way)?
         -- In that case we should not evaluate y before the call to 'foo'.
         -- Hackish solution: spot the IO-like situation and add a virtual
 branch,
         -- as if we had
         --      case foo x s of
         --         (# s, r #) -> y
         --         other      -> return ()
         -- So the 'y' isn't necessarily going to be evaluated
         --
         -- A more complete example (Trac #148, #1592) where this shows up
 is:
         --      do { let len = <expensive> ;
         --         ; when (...) (exitWith ExitSuccess)
         --         ; print len }
 }}}
 Now, Roman has discovered something else.
  * Not only is the hack unsavory,
  * not only does it make `loop` lazy when it should be strict,
  * but in addition it is incredibly fragile.
 By not-inlining `f` the hack doesn't fire, and `loop` gets stricter!  This
 is simply unacceptable.

 I don't really know what the right thing to do is.  I'm very inclined
 simply to remove the hack and see whether anyone complains.  But I'm open
 to suggestions.

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5775#comment:4>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler

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

Reply via email to