#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
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs