
What is really frustrating is that GHC has the machinery to do this trivially (RULES, soon core2core phase plugins as well), only that this machinery gets applied when source location information is no longer available, so it is useless for this problem:-(
I'd be happy to be proven wrong in this, of course!-) I had the feeling that there'd been some recent work on all this and, indeed, reddit has: http://www.reddit.com/r/haskell/comments/8mbar/finding_the_needle_stack_trac... Right on topic, and I assume the authors are on this list!-) It appears that the bulk of the paper is concerned with performance improvements - if we just want to recreate the user view, the mapException approach would appear to be a lot simpler (perhaps the paper could discuss it as a poor man's alternative, in particular since its source rewrites seem less intrusive?). Of course, having any support for this in GHC will be an improvement. However, it is interesting that the paper suggests an implementation using a core2core transformation, *with access to source location l*: [|x_l|]s = x deb (push l s), if x has (Debugged ’x deb) ann (Figure 1, page 4) Does that mean it would be possible to add an extension to RULES that would allow things like: {-# RULES "f->f_" forall x. f{SRCLOC} x = mapError SRCLOC (f_ x) #-} ie, referring to the source location of 'f' in the right hand side? That would seem to be the smallest possible change permitting a user-level implementation of error stack traces. And it might be more generally useful as well. Attached is another example source, again doing the expansion by hand ( (f x) -> mapError SRCLOC (f x); error ".." -> errorSrc SRCLOC "..") and relying on mapException to collect the traces, with a few recursive examples suggested by the paper, and three variations of eliding recursive call sites from the stack traces (note that this only elides when presenting the trace, the real implementation from the paper elides when constructing the trace). Claus ------------------------------------ example output: $ ghc -e main stacktraces.hs -DPLAIN -- fib 5 fib with non-positive number: 0 ("stacktraces.hs",46) ("stacktraces.hs",45) ("stacktraces.hs",45) ("stacktraces.hs",45) ("stacktraces.hs",45) ("stacktraces.hs",36) -- odd_ 5 odd_: no match ("stacktraces.hs",51) ("stacktraces.hs",54) ("stacktraces.hs",50) ("stacktraces.hs",54) ("stacktraces.hs",50) ("stacktraces.hs",38) -- firstLetters2 Prelude.head: empty list ("stacktraces.hs",58) ("stacktraces.hs",62) ("stacktraces.hs",62) ("stacktraces.hs",62) $ ghc -e main stacktraces.hs -- fib 5 fib with non-positive number: 0 ("stacktraces.hs",46) ... ("stacktraces.hs",45) ("stacktraces.hs",36) -- odd_ 5 odd_: no match ("stacktraces.hs",51) ... ("stacktraces.hs",54) ("stacktraces.hs",50) ("stacktraces.hs",38) -- firstLetters2 Prelude.head: empty list ("stacktraces.hs",58) ... ("stacktraces.hs",62)