[Haskell-cafe] ($) not as transparent as it seems

John Meacham john at repetae.net
Fri Feb 4 00:05:36 CET 2011


In general, errors are always interchangeable with another. An
exception in haskell is a value, rather than an event. Haskell
prescribes no evaluation order other than if the result is defined it
must be equivalant to the one generated by a normal-order reduction
strategy. Since error is not a valid value, any behavior including
just locking up is a completely acceptable (if not very friendly)
thing for a compiler to do.

In practice, we like writing compilers that help us find our errors
and using compilers that don't obfuscate them so compilers tend to
behave more or less like youd expect when presented with error, but
not at the expense of optimization or other necessary transformations.

 GHC has stronger guarentees in order to support its imprecise
exceptions extension in that the exceptional value returned is
guarenteed to be (non-deterministically) selected from the set of all
possible errors for every possible evaluation order of the expression.
So It won't just conjure up something new out of thin air, but neither
can you expect any particular exception when your code can produce
more than one.

    John

On Thu, Feb 3, 2011 at 2:42 PM, Dan Doel <dan.doel at gmail.com> wrote:
> On Thursday 03 February 2011 5:12:54 PM Tim Chevalier wrote:
>> On Thu, Feb 3, 2011 at 2:03 PM, Luke Palmer <lrpalmer at gmail.com> wrote:
>> > This is probably a result of strictness analysis.  error is
>> > technically strict, so it is reasonable to optimize to:
>> >
>> >    let e = error "foo" in e `seq` error e
>>
>> Yes, and you can see this in the Core code that Don posted: in version
>> (A), GHC optimized away the outer call to error. But in version (B),
>> the demand analyzer only knows that ($) is strict in its first
>> argument -- it's not strict in its second. So it's not obviously safe
>> to do the same optimization: the demand analyzer doesn't "look
>> through" higher-order function arguments IIRC. (You can confirm this
>> for yourself if you also want to read the demand analyzer output.)
>>
>> If ($) were getting inlined, the code would look the same coming into
>> demand analysis in both cases, so you wouldn't see a difference. So
>> I'm guessing you're compiling with -O0.
>
> Whatever is going on, it has to be active during ghci, because all these
> differences can be seen during interpretation (in 7.0.1, at least).
>
>  Prelude> error (error "foo")
>  *** Exception: foo
>  Prelude> error $ error "foo"
>  *** Exception: *** Exception: foo
>  Prelude> let g :: (a -> b) -> a -> b ; g f x = f x in g error (error "foo")
>  *** Exception: foo
>  Prelude> let g :: (a -> b) -> a -> b ; g f x = f x
>  Prelude> g error (error "foo")
>  *** Exception: *** Exception: foo
>  Prelude> let foo = error "foo" in error foo
>  *** Exception: foo
>  Prelude> let foo = error "foo"
>  Prelude> error foo
>  *** Exception: *** Exception: foo
>
> Actually compiling seems to remove the difference in 7.0.1, at least, because
> the output is always:
>
>  Foo: foo
>
> regardless of ($) or not ('fix error' hangs without output as well, which
> isn't what I thought would happen).
>
> Anyhow, that rules out most general-purpose optimizations (including
> strictness analysis, I thought).
>
> - Dan
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>



More information about the Haskell-Cafe mailing list