[Haskell-cafe] Re: Error message reform
wren ng thornton
wren at freegeek.org
Sun May 31 18:02:37 EDT 2009
Tillmann Rendel wrote:
> wren ng thornton wrote:
> > (Though it doesn't necessarily generalize to cover similar messages like:
> >
> > Prelude> :t (\x -> x) :: a -> b
> > <interactive>:1:7:
> > Couldn't match expected type `b' against inferred type `a'
> > `b' is a rigid type variable bound by
> > the polymorphic type `forall a b. a -> b' at <interactive>:1:0
> > `a' is a rigid type variable bound by
> > the polymorphic type `forall a b. a -> b' at <interactive>:1:0
> > In the expression: x
>
> I find this slightly more complicated case quite confusing with the
> current wording:
>
> Prelude> :t (\x -> x) :: (a -> b) -> (a -> a)
> <interactive>:1:7:
> Couldn't match expected type `a' against inferred type `b'
> `a' is a rigid type variable bound by
> an expression type signature at <interactive>:1:14
> `b' is a rigid type variable bound by
> an expression type signature at <interactive>:1:19
> In the expression: x
> In the expression: (\ x -> x) :: (a -> b) -> (a -> a)
>
> This message suggests that ghc has inferred type b for x.
I agree with Claus that this (both of these, actually) are symptoms of
not giving enough type information for the user to reconstruct what the
problem actually is.
I think an initial solution should be to print out _some_ type inferred
for x. We can't print out "the" type, because the error is that there
isn't one. As for which type to print for x, it'd be most informative
(though perhaps not most helpful) to print both types that are being
unified, and to alter the rigidity messages to indicate which type
they're rigid for. For example, perhaps something like this:
Couldn't match expected type `a' against inferred type `b'
In the expression: x
which should have type: (a -> a)
where `a' is a rigid type variable bound by
an expression with type signature at <interactive>:1:14
but actually has type: (a -> b)
where `b' is a rigid type variable bound by
an expression with type signature at <interactive>:1:19
In the expression: (\ x -> x) :: (a -> b) -> (a -> a)
It's too wordy, but it's a start. This is also prime ground for wanting
to have configurable levels of error reports, since some users will find
it helpful to see both types but others will find it confusing.
Sometimes, even when the complete type is given, that's not enough
information because each of the type variables are non-linear and so
it's not clear where exactly the problem crept up. We can see a little
of this in the above example where, even with the new message, `a'
occurs twice in the first type. By presenting both types, users can
figure it out here--- though with only the last type signature given it
wouldn't be clear whether it wants ((b->b)->a->a) or ((a->b)->a->b) or
even ((a->b)->b->a).
In more complex examples I've often found non-linearity to be the most
uninformative part of the current messages. Perhaps a message like above
which gives both types will be enough in practice to clear it up. If
not, then it may be worth providing some sort of metasyntax to
distinguish what subpart of the type is being discussed (e.g. bold face,
or an underlining carrot on the next line, etc).
For really intricate type hacking, even this isn't enough because the
programming errors often happen far from where the type errors are
finally caught. In an ideal world, ghc could dump the entire proof
forest generated by inference, so an external tool[1] could be used to
browse through it and track the complete history of where inferred types
came from. This gives a partial view of the inferred types for a
compilation unit, something I've often wanted (rather than the manual
comment/reload/uncomment routine). The proof forest could even be used
as an interlingua over which people can write filters to generate
messages they find most helpful.
Ah the joys of ideal worlds... ;)
[1] Something like the Dynasty[2] debugger for logic programming in Dyna.
[2] http://www.cs.jhu.edu/~jason/papers/eisner+al.infovis06-poster.pdf
--
Live well,
~wren
More information about the Haskell-Cafe
mailing list