Inspired by this reddit discussion, I'm wondering if there are any technical obstacles in the way of a "Dr Scheme"-style approach to assisting beginners when it comes to comprehending error messages. A case in point is the notorious
Prelude> 1 "doesn't"
<interactive>:3:1:
No instance for (Num ([Char] -> t0))
arising from the literal `1'
Possible fix: add an instance declaration for (Num ([Char] -> t0))
In the expression: 1
In the expression: 1 "doesn't"
In an equation for `it': it = 1 "doesn't"
Suppose we were to make the local assumption that the programmer will declare no new instances. Indeed, one can get a long way in Haskell interacting with only prelude classes only via deriving
, so this assumption is not unrealistic for beginners. Under such an assumption, the above error message would be beside the point. Could we improve upon it? We might still need to figure out how much to say about the type of 1
, but we could surely be more direct about the problem.
Are there other opportunities to reframe error messages on the basis of realistic simplifying assumptions? Note, I'm asking a question about changing the text of error messages based on a model of the programmer's experience: I am not locally considering any changes to which code is considered erroneous (e.g., by assuming that beginners will use overloaded things at specialised types, eliminating ambiguity).
A follow-up thought: does the text of the existing error messages contain enough information to support such transformations, assuming a "configuration file" modelling the student? That is, could an enterprising hacker implement an intelligibility-enhancing postprocessor for ghci
without troubling the busy people at HQ?
An error message is a message displayed to the user by an operating system or application when an unexpected condition happens. In most cases, error messages are displayed with the help of dialog boxes by the operating system or application.
Error messages are used when user intervention is required, to indicate that a desired operation has failed, or to relay important warnings (such as warning a computer user that they are almost out of hard disk space).
I'm not convinced that ignoring certain features for the sake of error messages would be helpful.
For one thing, are the errors encountered by beginners really that different from anyone else? Just because I know how to interpret a "no Num instance for this absurd thing which is clearly not a numeric type" error doesn't mean I wouldn't appreciate GHC more clearly pointing out what bone-headed thing I've done to provoke such a message.
I would suggest that the circumstances in which a beginner or an expert would be writing instances, or any other kind of "advanced" code, differ very little. The beginner, however, will be coding under those circumstances far less often, with an inclusive lower bound of "never".
If one wishes to insulate beginners from arcane corners of the language, then make sure they don't encounter them at all. For instance (ha, ha), there's an argument to be made for avoiding type classes entirely when first introducing the language.
I can't think of any cases where a more beginner-friendly error message, so long as it doesn't throw away information, would not also be more pleasant for everyone else as well.
Suppose we were to make the local assumption that the programmer will declare no new instances.
Suppose we instead make the assumption that the programmer will declare no orphan instances where the class and/or type are defined by the Haskell Report. This assumption is most assuredly realistic for beginners and, in fact, seems reasonable as a general rule.
Adding such an instance because of a compiler error at all is plausible in very few situations. With the glaring and galling exception of the anonymous writer monad (unless that has been remedied since I last checked) orphan instances for a standard class and type seems exceedingly unlikely, and one or the other should only arise when a library has unexpectedly overlooked a few instances, or is old and dusty enough to predate the prevalence of stuff like Applicative
or Foldable
. In any case, anyone who does want such an instance can be safely assumed to know what they're doing well enough to interpret GHC's error message, whatever it may be.
But enough about that particular example.
Are there other opportunities to reframe error messages on the basis of realistic simplifying assumptions?
Very likely, but we're also very far from exhausting the space of realistic complicating assumptions!
The point of the above digression on instances is that by using information already available to the compiler and heuristics that examine a larger context (e.g., where certain things are defined, to distinguish the above example from non-orphan instances) error messages could be improved in general.
A follow-up thought: does the text of the existing error messages contain enough information to support such transformations, assuming a "configuration file" modelling the student?
I really can't see this working very well except in the simplest and most egregious cases, the example you gave being a notable example. It could rephrase existing flavors of error, but beginners would benefit most from having more detailed/explicit information that the existing message may not contain.
Consider two other error messages that are chronically vexing to beginners: complaints about matching "rigid type variables", and complaints about "infinite types". Rephrasing might improve those somewhat, but short of including a tutorial on polymorphism in each error message it's not going to much help a beginner fix their code, unless you can interpret the relevant expression and type well enough to be specific about the cause.
Together with inspecting the source code a "translator" might have some legs, but I suspect modifying GHC directly will quickly become the easiest route. Generating error messages would be an interesting extensibility point, but I don't think this can be done with GHC's existing plugin infrastructure.
The greatest obstacle to any of this, I expect, is not implementation. Rather, it's the decision of which heuristics would improve error messages rather than accomplishing the opposite. Without a base of objective data, this is something of an error-prone (ha, ha) guessing game. It would be very interesting to assemble a large survey of errors encountered by (primarily intermediate or novice) Haskell programmers and, most importantly, what actual change they made to resolve the issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With