
fun x y = let f1 = ... (f2 x) ... -- f1 calls f2 f2 x = x * 2 in case x of 1 -> f2 0 _ -> f2 (f1 y)
g x = let z = (some complex computation) in z `div` x
main = print (g (fun 1 2))
This is a classical example of why laziness gets in the way of debugging. Now, when (f2 0) gets finally evaluated and throws a divByZero error, x and y are nowhere to be found. Since we do not have a real dynamic stack, it is difficult to say where their values should be stored. The only place I can think of is at the breakpoint itself, but then as Simon said this poses a serious efficiency problem.
Isn't that a case of premature optimization? I will happily compain about performance issues later, after the debugger turns out to be merely too slow!-) Currently, the issue is one of it not working as well as it could, which seems rather more important to me (think of it as infinitely too slow for my needs:-). Once it comes to performance issues (btw, is there a debugger home page on the wiki, where issues/FAQs like "why can't I have scope contexts" are documented?), an obvious compromise would be to state explicitly where to preserve scope information - something like: :break fun{x,y}/{f1,f2}/f2{x} would set a breakpoint on f2, associating with it information about the static scope context including only the named names (items between // define the path towards the name we want to break, level by level; additional names can be added in {} at each level), without affecting other parts of the program. Claus