<div class="gmail_quote">2009/4/28 Thomas Hartman <span dir="ltr"><<a href="mailto:tphyahoo@gmail.com">tphyahoo@gmail.com</a>></span></div><div class="gmail_quote"><span dir="ltr"></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
I suppose this means that the points-free/pattern binding-style<br>
version is a bit less work for ghc to execute (fewer reductions),<br>
whereas the version with lambda bound variables is easier to debug.</blockquote><div><br></div><div>I don't think there is any (significant) difference between them in the amount of work done at runtime. The observed difference in behaviour is more a matter of how the debugging transformation in GHCi interprets the command "set a breakpoint on f", and how the code for f is generated.</div>
<div><br></div><div>I think my previous email was slightly misleading, and we should be careful to distinguish between 'evaluating f' and 'evaluating applications of f'. In both cases f is already a value (either a partial application or a lambda function). So f itself doesn't really undergo 'reduction', in the theoretical sense. However, a compiler, such as GHC, may generate code which does a little bit of work at runtime, and the debugger may be able to observe that work. When f is written in the pattern binding style, the breakpoint on f reveals the 'evaluation of f', which is just the little bit of work at runtime I was talking about. When f is written in function binding style, the breakpoint on f reveals 'an evaluation of an application of f' (which may happen more than once).</div>
<div><br></div><div>Normally, when people attach a breakpoint on a function, they want to see the evaluation of applications of the function. So the behaviour of the debugger for functions defined in the pattern binding style can be confusing.</div>
<div><br></div><div>The debugger could arrange things so that both styles of definition give the same behaviour wrt breakpoints, for example by eta-expanding definitions.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
On balance, I think I'll frequently write my functions with lambda<br>
bound variables then.</blockquote><div><br></div><div>It does seem a shame to modify your code style for the sake of the debugger, but I guess that is inevitable with procedural debuggers anyway.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
2009/4/26 Bernie Pope <<a href="mailto:florbitous@gmail.com">florbitous@gmail.com</a>>:<br>
<div><div></div><div class="h5">> 2009/4/25 Thomas Hartman <<a href="mailto:tphyahoo@gmail.com">tphyahoo@gmail.com</a>><br>
>><br>
>> In the program below, can someone explain the following debugger output to<br>
>> me?<br>
>><br>
>> After :continue, shouldn't I hit the f breakpoint two more times?<br>
>> Why do I only hit the f breakpoint once?<br>
>> Is this a problem in the debugger?<br>
>><br>
>> thartman@ubuntu:~/haskell-learning/debugger>cat debugger.hs<br>
>><br>
>> -- try this:<br>
>> -- ghci debugger.hs<br>
>> -- > :break f<br>
>> -- > :trace t<br>
>> -- > :history -- should show you that f was called from h<br>
>> t = h . g . f $ "hey!"<br>
>> t2 = h . g . f $ "heh!"<br>
>> t3 = h . g . f $ "wey!"<br>
>><br>
>> f = ("f -- " ++)<br>
>> g = ("g -- " ++)<br>
>> h = ("h -- " ++)<br>
>><br>
>> ts = do<br>
>> putStrLn $ t<br>
>> putStrLn $ t2<br>
>> putStrLn $ t3<br>
><br>
> What you are observing is really an artifact of the way breakpoints are<br>
> attached to definitions in the debugger, and the way that GHCi evaluates<br>
> code.<br>
> f is clearly a function, but its definition style is a so-called "pattern<br>
> binding". The body contains no free (lambda bound) variables, so it is also<br>
> a constant. GHCi arranges for f to be evaluated at most once. The breakpoint<br>
> associated with the definition of f is fired if and when that evaluation<br>
> takes place. Thus, in your case it fires exactly once.<br>
> You can re-write f to use a so-called "function binding" instead, by<br>
> eta-expansion (introduce a new fresh variable, and apply the function to it<br>
> on both sides):<br>
> f x = ("f -- " ++) x<br>
> This denotes the same function, but the breakpoint on f works differently.<br>
> In this case, a breakpoint attached to f will fire whenever an application<br>
> of f is reduced. If you write it this way you will see that the program<br>
> stops three times instead of one.<br>
> You might ask: if both definitions denote the same function, why does the<br>
> debugger behave differently? The short answer is that the debugger in GHCi<br>
> is an operational debugger, so it exposes some of the operational details<br>
> which may be invisible in a denotational semantics. In this case it revels<br>
> that GHCi treats the two definitions of f differently.<br>
> Cheers,<br>
> Bernie.<br>
><br>
</div></div></blockquote></div><br>