Re: [Haskell-cafe] ghci debugger problem with :continue. is it broken, or is it me?
2009/4/28 Thomas Hartman I suppose this means that the points-free/pattern binding-style > version is a bit less work for ghc to execute (fewer reductions), > whereas the version with lambda bound variables is easier to debug. 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. 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). 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. The debugger could arrange things so that both styles of definition give the same behaviour wrt breakpoints, for example by eta-expanding definitions. On balance, I think I'll frequently write my functions with lambda > bound variables then. 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. > > 2009/4/26 Bernie Pope : > > 2009/4/25 Thomas Hartman > >> > >> In the program below, can someone explain the following debugger output > to > >> me? > >> > >> After :continue, shouldn't I hit the f breakpoint two more times? > >> Why do I only hit the f breakpoint once? > >> Is this a problem in the debugger? > >> > >> thart...@ubuntu:~/haskell-learning/debugger>cat debugger.hs > >> > >> -- try this: > >> -- ghci debugger.hs > >> -- > :break f > >> -- > :trace t > >> -- > :history -- should show you that f was called from h > >> t = h . g . f $ "hey!" > >> t2 = h . g . f $ "heh!" > >> t3 = h . g . f $ "wey!" > >> > >> f = ("f -- " ++) > >> g = ("g -- " ++) > >> h = ("h -- " ++) > >> > >> ts = do > >> putStrLn $ t > >> putStrLn $ t2 > >> putStrLn $ t3 > > > > What you are observing is really an artifact of the way breakpoints are > > attached to definitions in the debugger, and the way that GHCi evaluates > > code. > > f is clearly a function, but its definition style is a so-called "pattern > > binding". The body contains no free (lambda bound) variables, so it is > also > > a constant. GHCi arranges for f to be evaluated at most once. The > breakpoint > > associated with the definition of f is fired if and when that evaluation > > takes place. Thus, in your case it fires exactly once. > > You can re-write f to use a so-called "function binding" instead, by > > eta-expansion (introduce a new fresh variable, and apply the function to > it > > on both sides): > >f x = ("f -- " ++) x > > This denotes the same function, but the breakpoint on f works > differently. > > In this case, a breakpoint attached to f will fire whenever an > application > > of f is reduced. If you write it this way you will see that the program > > stops three times instead of one. > > You might ask: if both definitions denote the same function, why does the > > debugger behave differently? The short answer is that the debugger in > GHCi > > is an operational debugger, so it exposes some of the operational details > > which may be invisible in a denotational semantics. In this case it > revels > > that GHCi treats the two definitions of f differently. > > Cheers, > > Bernie. > > > ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ghci debugger problem with :continue. is it broken, or is it me?
Most enlightening, thanks. The same effect can be seen with Debug.Trace.trace around the two versions of f. I suppose this means that the points-free/pattern binding-style version is a bit less work for ghc to execute (fewer reductions), whereas the version with lambda bound variables is easier to debug. On balance, I think I'll frequently write my functions with lambda bound variables then. Getting better use out of the ghc debugger seems worth the few extra cycles. 2009/4/26 Bernie Pope : > 2009/4/25 Thomas Hartman >> >> In the program below, can someone explain the following debugger output to >> me? >> >> After :continue, shouldn't I hit the f breakpoint two more times? >> Why do I only hit the f breakpoint once? >> Is this a problem in the debugger? >> >> thart...@ubuntu:~/haskell-learning/debugger>cat debugger.hs >> >> -- try this: >> -- ghci debugger.hs >> -- > :break f >> -- > :trace t >> -- > :history -- should show you that f was called from h >> t = h . g . f $ "hey!" >> t2 = h . g . f $ "heh!" >> t3 = h . g . f $ "wey!" >> >> f = ("f -- " ++) >> g = ("g -- " ++) >> h = ("h -- " ++) >> >> ts = do >> putStrLn $ t >> putStrLn $ t2 >> putStrLn $ t3 > > What you are observing is really an artifact of the way breakpoints are > attached to definitions in the debugger, and the way that GHCi evaluates > code. > f is clearly a function, but its definition style is a so-called "pattern > binding". The body contains no free (lambda bound) variables, so it is also > a constant. GHCi arranges for f to be evaluated at most once. The breakpoint > associated with the definition of f is fired if and when that evaluation > takes place. Thus, in your case it fires exactly once. > You can re-write f to use a so-called "function binding" instead, by > eta-expansion (introduce a new fresh variable, and apply the function to it > on both sides): > f x = ("f -- " ++) x > This denotes the same function, but the breakpoint on f works differently. > In this case, a breakpoint attached to f will fire whenever an application > of f is reduced. If you write it this way you will see that the program > stops three times instead of one. > You might ask: if both definitions denote the same function, why does the > debugger behave differently? The short answer is that the debugger in GHCi > is an operational debugger, so it exposes some of the operational details > which may be invisible in a denotational semantics. In this case it revels > that GHCi treats the two definitions of f differently. > Cheers, > Bernie. > ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] ghci debugger problem with :continue. is it broken, or is it me?
2009/4/25 Thomas Hartman > In the program below, can someone explain the following debugger output to > me? > > After :continue, shouldn't I hit the f breakpoint two more times? > Why do I only hit the f breakpoint once? > Is this a problem in the debugger? > > thart...@ubuntu:~/haskell-learning/debugger>cat debugger.hs > > -- try this: > -- ghci debugger.hs > -- > :break f > -- > :trace t > -- > :history -- should show you that f was called from h > t = h . g . f $ "hey!" > t2 = h . g . f $ "heh!" > t3 = h . g . f $ "wey!" > > f = ("f -- " ++) > g = ("g -- " ++) > h = ("h -- " ++) > > ts = do > putStrLn $ t > putStrLn $ t2 > putStrLn $ t3 What you are observing is really an artifact of the way breakpoints are attached to definitions in the debugger, and the way that GHCi evaluates code. f is clearly a function, but its definition style is a so-called "pattern binding". The body contains no free (lambda bound) variables, so it is also a constant. GHCi arranges for f to be evaluated at most once. The breakpoint associated with the definition of f is fired if and when that evaluation takes place. Thus, in your case it fires exactly once. You can re-write f to use a so-called "function binding" instead, by eta-expansion (introduce a new fresh variable, and apply the function to it on both sides): f x = ("f -- " ++) x This denotes the same function, but the breakpoint on f works differently. In this case, a breakpoint attached to f will fire whenever an application of f is reduced. If you write it this way you will see that the program stops three times instead of one. You might ask: if both definitions denote the same function, why does the debugger behave differently? The short answer is that the debugger in GHCi is an operational debugger, so it exposes some of the operational details which may be invisible in a denotational semantics. In this case it revels that GHCi treats the two definitions of f differently. Cheers, Bernie. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] ghci debugger problem with :continue. is it broken, or is it me?
In the program below, can someone explain the following debugger output to me? After :continue, shouldn't I hit the f breakpoint two more times? Why do I only hit the f breakpoint once? Is this a problem in the debugger? thart...@ubuntu:~/haskell-learning/debugger>cat debugger.hs -- try this: -- ghci debugger.hs -- > :break f -- > :trace t -- > :history -- should show you that f was called from h t = h . g . f $ "hey!" t2 = h . g . f $ "heh!" t3 = h . g . f $ "wey!" f = ("f -- " ++) g = ("g -- " ++) h = ("h -- " ++) ts = do putStrLn $ t putStrLn $ t2 putStrLn $ t3 {- Problems using :continue in the ghci debugger? Can someone explain the following debugger output to me? After :continue, shouldn't I hit the f breakpoint two more times? Why do I only hit the f breakpoint once? Is this a problem in the debugger? thart...@ubuntu:~/haskell-learning/debugger>ghci debugger.hs GHCi, version 6.10.1: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer ... linking ... done. Loading package base ... linking ... done. [1 of 1] Compiling Main ( debugger.hs, interpreted ) Ok, modules loaded: Main. *Main> :break f Breakpoint 0 activated at debugger.hs:12:4-15 *Main> ts h -- g -- Stopped at debugger.hs:12:4-15 _result :: [Char] -> [Char] = _ 11 12 f = ("f -- " ++) 13 g = ("g -- " ++) [debugger.hs:12:4-15] *Main> :continue f -- hey! h -- g -- f -- heh! h -- g -- f -- wey! *Main> -} ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe