
the mapException approach
I'm afraid it won't work as you hope for functions that return lazy data structures. The 'evaluate' implicit in mapException only catches top-level errors/exceptions, like 'seq' and not like 'deepSeq'.
Have a look at 'firstLetters2' in the example I provided. Perhaps it is easier to see if you change the 'map_' to 'map', or at least put the definition on two lines (since the CPP-based SRCLOC doesn't include columns), but it is there in any case. The initial call to 'map_' is not part of the stack trace, nor are any of the recursive calls. Nor should they be, I think - if 'map' delivers as much as '[]' or 'undefined : undefined' without raising an error, it has done its job. If evaluating any part of the non-strict data structure runs into trouble, the inspection, not the generation, is to blame. That may be inconvenient when one actually wants to see where the parts of the data structure came from, but there are established techniques for forcing strictness, or one can annotate data with producer info (in ways similar to what Hood does: make sure the producer info is there if the part is ever inspected, but don't actually force the part). Here is a slightly rewritten 'firstLetters2', to illustrate: firstLetters2 = mapError SRCLOC $ -- 58 map_ (mapError SRCLOC . head) ["hi", "world", "", "!"] -- 59 map_ f [] = [] map_ f (h:t) = f1 h : mapError SRCLOC (map_ f2 t) -- 62 where f1 = mapError SRCLOC . f -- 63 f2 = mapError SRCLOC . f -- 64 and here is the relevant part of the output (using -DPLAIN): -- firstLetters2 Prelude.head: empty list ("stacktraces.hs",59) ("stacktraces.hs",64) ("stacktraces.hs",64) ("stacktraces.hs",63) Neither 58 nor 62 appear in the trace (there is nothing wrong with 'map_'). The appearance of 63 and 64 in the trace gives one simple example of how information can be added without prematurely forcing evaluation (eg, 'head firstLetters2' gives no trace at all). Claus