Specialized type hints
eric at seidel.io
Thu Mar 3 16:58:13 UTC 2016
On Wed, Mar 2, 2016, at 23:54, Christopher Allen wrote:
> I'd like to see how warm people would be to catching GHC's type error
> quality up a bit.
> I did a write-up on a confusion a reader of our book had:
Wow, this is a pretty nasty error message. In particular because it
relies on the overloaded nature of integer literals. Compare
ghci> negate * 10
Non type-variable argument in the constraint: Num (a -> a)
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall a. (Num a, Num (a -> a)) => a -> a
ghci> negate * (10 :: Int)
Couldn't match expected type ‘a -> a’ with actual type ‘Int’
Relevant bindings include it :: a -> a (bound at <interactive>:4:1)
In the second argument of ‘(*)’, namely ‘(10 :: Int)’
In the expression: negate * (10 :: Int)
In an equation for ‘it’: it = negate * (10 :: Int)
In the first case (your example), GHC actually finds a valid type for
the expression (assuming FlexibleContexts) because `10` is actually
`fromIntegral 10`, which is overloaded. On the other hand, if you
constrain `10` to be an `Int` there's an immediate unification error,
which is much more helpful.
> This is not new. A lot of people complain about this particular type
> in particular when they say GHC has bad type errors. I don't think GHC's
> type errors are bad, but I do think they could be improved and this
> particular issue has an unfortunate source to sink distance.
> I would rather type error improvements not be buried behind a "silly
> beginners only" flag and that they just be part of improving the UX for
> everyone. With that proviso, how likely would specialized type error
> and some general error message fix ups be regarded?
> By specialized I mean, "detect that they tried to find an instance of Num
> for (-> something something) and suggest that they did the wrong thing,
> with possible fixes: X Y Z". Ideally before the "hey do you want
> FlexibleContexts?!" thing fires.
> I do not think I am capable of doing this, but being able to zoom in,
> style, to the expression where they are (probably accidentally) using a
> function like a Num or a Num like a function would be pretty valuable so
> they don't have to guess-n-check parenthesize their code.
One thing I've noticed other compilers doing (and this might be exactly
what you're hinting at) is provide a sort of provenance of the error, in
the form of warnings and notes. For example, even though using `*` at
`Num (a -> a)` isn't immediately bogus, it is suspicious, so we could
record a note and print it out alongside the error message, should one
The other thing we could do, which I think would help novices in
particular, is to just allow you to run ill-typed programs in ghci.
Running the program in a debugger gives you so much more information
about what's going on. You did exactly that at the top of your link, but
you had to write out the steps manually, whereas we could have a machine
do it for us! (In fact, I've been working on this lately, albeit for
ocaml programs since we teach ocaml to our undergrads. I think the
results are quite nice http://goto.ucsd.edu:8091)
More information about the ghc-devs