views:

129

answers:

2

Is there a way to get GHCi to produce better exception messages when it finds at runtime that a call has produced value that does not match the function's pattern matching?

It currently gives the line numbers of the function which produced the non-exhaustive pattern match which though helpful at times does require a round of debugging which at times I feel is doing the same set of things over and over. So before I tried to put together a solution I wanted to see if something else exists.

An exception message that in addition to giving the line numbers shows what kind of call it attempted to make?

Is this even possible?

+4  A: 

Try turning on warnings in ghci. This enables the compile time warnings you can get with ghc by passing -W, for example. You can do this several ways:

ghci -fwarn-incomplete-patterns

Or Neil Mitchell describes how he sets this up in his .ghci. Here is the relevant excerpt:

:set -fwarn-incomplete-patterns

You can manually enter this at ghci as well, but it would be a pain to do so each time you start it. Entered this way, it only works for statements entered at the prompt, not for loading files with :l. Instead you can put this comment at the top of the file you want to warn about incomplete patterns:

{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
Nathan Sanders
Sadly this does not always warn as far as I can see... I just tried it and no luck, thanks anyways!
toofarsideways
Apparently this only applies to statements typed in at ghc and not loaded from files. I updated my answer to work for that too.
Nathan Sanders
Thank you, just what I needed!
toofarsideways
For what it's worth, when I tried it, invoking GHCi with the actual command line options directly seemed to enable it for both loaded files and statements typed in at the prompt.
camccann
+1  A: 

I recognize that this is something of a non-answer to your question, but my impression is that among veteran Haskell programmers there's a general consensus that non-exhaustive patterns should be avoided in the first place, even to the point of using -Werror to generate errors instead of just warnings.

I'm not sure how well that works in combination with GHCi, however, especially if you're writing functions at the prompt instead of loading a file--I can imagine it getting in the way more than it helps for working interactively. Running GHCi with the appropriate command-line flags seems to get the desired result for me, though.

If you want a more drastic solution to non-exhaustive patterns, you could always port Catch to work with modern GHC versions. Heh.

Beyond that, if you're using non-exhaustive patterns because the function really, truly, should never be called with some values, the missing cases can be filled in with something like error $ "function foo called with ridiculous arguments " ++ show blahBlah, if knowing the invalid arguments would be helpful. Alternately, you could try to rework your code or define more specialized data types such that functions can always do something sensible with any non-bottom argument.

Otherwise, I think you're stuck with awkward debugging.

camccann
That is a good point, for the moment I doubt I can follow that rule but I'm due for a refactoring session soon so turning that on and fixing everything that comes up will soon be on that list. Thank you for the show tip, I didn't know you could structure an error in this fashion. I was deploring getting some useful errors out as I haven't seen that style being used. Other than throwing an error along the lines of error "abandon ship at function foo"
toofarsideways
@toofarsideways: `error` is just a function that takes an arbitrary `String` for the error message; you can do whatever you want to create the string. You may also want to look at the `Debug.Trace` module if you haven't already, for a quick and dirty Haskell version of old-fashioned "printf debugging". As far as using `error` goes it's probably bad style for production code, but is fine for development/testing.
camccann
Thank you, worth looking into :). I had been scratching my head on how to do that...
toofarsideways