Is Levenshtein distance the right metrics to use? Levenshtein distance counts each addition, deletion, and substitution as one. But does substitution make sense here? Should I compute the residue of longest common subsequence instead?
The following might be "the perfect (or better) is the enemy of the good" material --- if so I hope you ignore it!!
I wonder should there be some protocol to expose one or more resolutions? A default handler could print those (as in your example). But a tool could present a choice to the user, and even take action on the choice.
Sometimes I make a typo intending an imported identifier (your example above). There may be one or more imported identifiers that I intended. I could choose which, and the tool will correct it for me.
Sometimes I type a valid identifier... the problem is I forgot to import it. There may be one or more modules that export it. I could choose which, and the tool will add the missing require.
It's possible 1 by itself might try to match something already imported, when the actual problem is 2.
Part of me feels like this would fit well with check-syntax... but maybe that assumes too much for all tools that would want to use this.
This reminds me of some work @notjack did for a framework for "linting" IIRC generally.
Again, apologies if this is an unwelcome detour, if so of course please just ignore me.
Finding what module must be imported to fix the error is a great idea! I will experiment with it. (This reminds me of all those memes where people install an exception handler to search StackOverflow.)
I consider repairing the mistake to be out of scope for this package. But, say, another DrRacket plugin package could definitely cooperate with this package to perform the actual repair.
Related: it seems interesting to me that this is enabled by a 'require', rather than by a DrRacket tool. I guess it's strange to me that the error message associated with an unbound identifier is actually part of the #lang definition, but I see how that would make sense. I ... think I'd be more likely to use something I can blanket-enable in the editor, though. It's an interesting area of crossover between the language and the editor. Thoughts about this?
This is very cool! (I'm sorry I missed it the first time!)
I wonder if the unbound identifier exception could be changed to include a syntax object that would have the information you'd want to use? It seems like the expander should have more information than it's currently reporting at that stage.
Ouch. Thanks for letting me know. Here's the content:
> (module test racket/base
->: unbound identifier
suggestion: do you mean `-'?
alternative suggestion: do you want to import one of the
following modules, which provides the identifier?
`racket/contract/base' or `racket/contract' or `racket'
`typed/racket/base' or `typed/racket'
Thanks to @greghendershott again for the recommendation to suggest modules to import.
My original intention is that a #lang might want to provide this capability by default, so I made this a library to allow that.
But I can see that making this a tool (e.g. raco helpful) could also be useful. I might add that next.
It's unclear how to make it integrate with DrRacket nicely as a plugin. The debugging component in DrRacket, which invokes errortrace that @gus-massa mentioned below, is tightly integrated with DrRacket. Though in the worst case I can add my own "Run" button, I guess...
I had hoped to spend some time working on this too but it looks like I'm not getting there But, FWIW, it would be great it just integrate this directly into the error reporting code in DrRacket itself somehow. There is code already that does special stuff to render exceptions that get raised. It does not seem difficult to augment that code so that it recognizes certain exceptions as containing free identifiers that it responds to by running an algorithm to offer some choices to fix them in the GUI.