Re: [Haskell-cafe] ghci debugger problem with :continue. is it broken, or is it me?

2009-04-28 Thread Bernie Pope
2009/4/28 Thomas Hartman tphya...@gmail.com

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 florbit...@gmail.com:
  2009/4/25 Thomas Hartman tphya...@gmail.com
 
  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/debuggercat 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-04-27 Thread Thomas Hartman
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 florbit...@gmail.com:
 2009/4/25 Thomas Hartman tphya...@gmail.com

 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/debuggercat 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-04-26 Thread Bernie Pope
2009/4/25 Thomas Hartman tphya...@gmail.com

 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/debuggercat 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?

2009-04-24 Thread 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/debuggercat 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/debuggerghci 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