Showing posts with label ghci_debugger. Show all posts
Showing posts with label ghci_debugger. Show all posts

Friday, September 22, 2006

The ICFP contest has a winner!



And no, this year Haskell is not the language of choice :(

Don't miss the video of the presentation at ICFP, seriously cool stuff, at least if you can follow the geeky -rather academia- jokes. Only by watching it you'll find out which is the super-cool multinational company that has conquered both 1st and 3rd prize this year.

#haskell managed to have 5 teams among the first 50: Lazy Bottoms, DunComLooLump, Deus Ex Machina, Team Roflcopter, and the Int-E lone ranger team. Not too shabby, though nothing compared to previous successes. None of the winners this year used a high-level language.

By the way, a few weeks ago I made a video to showcase the ghci debugger which used the ICFP contest task as an example. Watch it!

Debugging in Haskell

Some few days ago, an innocent query sparkled a fiery discussion in the Haskell mailing list, this time about the virtues and vices of debugging.

At the time I did put up a quick survey page in the wiki about the various debugging options available in Haskell (including the ghci debugger, of course!), but I didn't think about mentioning it here. A partial rip-off of that page follows.

Printf and friends
The simplest approach is to use Debug.Trace.trace:
trace :: String -> a -> a
When called, trace outputs the string in its first argument, before returning the second argument as its result.

A common idiom to trace a function is:
myfun a b | trace ("myfun " ++ show a ++ " " ++ show b) False = undefined
myfun a b = ...
The advantage is that disabling and enabling the trace takes only one line comment.
You must keep in mind that due to lazy evaluation your traces will only print if the value they wrap is ever demanded.

A more powerful alternative for this approach is Hood. Even if it hasn't been updated in some time, Hood works perfectly with the current ghc distribution. Even more, Hugs has it already integrated, see the manual page. Add an import Observe and start inserting observations in your code.
For instance:
import Hugs.Observe

f' = observe "Informative name for f" f
f x = if odd x then x*2 else 0
And then in hugs:
Main> map f' [1..5]
[2,0,6,0,10]

>>>>>>> Observations <<<<<<> 10
, \ 4 -> 0
, \ 3 -> 6
, \ 2 -> 0
, \ 1 -> 2
}
The evaluation outputs a report of all the invocations of f and their result.

I have a handy bogus Hugs.Observe module with no-ops for the observations so that I don't need to remove them manually, expecting that the compiler will optimize them away.

Dynamic breakpoints in GHCi
Finally, the GHCi Debugger project aims to bring dynamic breakpoints and intermediate values observation to GHCi in a near future. Right now the tool is only available from the site as a modified version of GHC, so unfortunately you will have to compile it yourself if you want to have it.

This tool allows to set breakpoints in your code, directly from the GHCi command prompt. An example session:
*main:Main> :break add Main 2
Breakpoint set at (2,15)
*main:Main> qsort [10,9..1]
Local bindings in scope:
x :: a, xs :: [a], left :: [a], right :: [a]

qsort2.hs:2:15-46> :sprint x
x = _
qsort2.hs:2:15-46> x
This is an untyped, unevaluated computation. You can use seq to
force its evaluation and then :print to recover its type
qsort2.hs:2:15-46> seq x ()
()
qsort2.hs:2:15-46> :p x
x - 10
Once a breakpoint is hit, you can explore the bindings in scope, as well as to evaluate any haskell expression, as you would do in a normal GHCi prompt. The ':print' command can be very useful to explore the lazyness of your code.

Tuesday, August 29, 2006

Darcs is broken



Darcs is broken. I found it out the hard way yesterday, while I was trying to commit my patches to the main trunk of GHC.
Essentially, my patches were living in a separate branch. Of course the Darcs model does not need the concept of branches, as traditional SCMs do, but the analogy works fine here.
The debugger is complete just in time for the 6.6 GHC release, and we were planning to include it in the candidate release yesterday Monday.

But Darcs planned otherwise. While my patches were on a branch, I had been careful to keep this branch sync'ed to the main trunk. This means pulling patches from the main trunk once a week or so and fixing any conflicts with my code. Since my patches are spread around several subsystems in the compiler, conflicts have arisen three or four times during these three months.
It turns out that since the last sync with the main trunk I did around the 22nd of August, a new patch has been commited which conflicts with my work. But this time Darcs has decided against simply doing the merge and calling conflict. Instead, it will diverge exponentially and hang.

I have tried everything! I switched to Linux, to Windows, to older versions, I tried all sort of Darcs tricks... to no avail.

What is more embarrassing, it turns out that this is a well-known issue of Darcs, and looks like there is no hope for a solution in the near future.

So now what? The maintainers of the Ghc repo are aware of this Darcs issue, and they have sensibly requested me to avoid pushing patches with conflicts into the main repo. Which means I have to manually re-record all my patches, by hand (with help of diff/patch), into the main trunk. This could take me several evenings, and is boring as hell!
Of course I could record a One Big Patch, but that's a less desirable solution.

I wish I had known about this issue of Darcs before.
I wish Darcs patch theory wasn't so broken in the first place.

[posted with ecto]

Thursday, July 06, 2006

Post war

Oh no. Look at this. Almost one month without posting. Look at all you have missed! I feel your pain.

I have been so busy working and coding that I completely forgot about my blog. That, or that I hate blogging. This is something that puzzles me. I love reading blogs, I know that. I especially love good writers, so maybe it's a problem of fear of comparison. Steve Yegge is a great writer. Much better than Paul Graham -I won't say sorry Steve, I know he is not reading this- . I especially dearly love the witches one, it reminds me of House. I've also been watching House a lot lately. Much better than the over hyped Lost or Prison Break if you ask me.

But honestly, during this month I've been doing some work too. I have actually managed to put up some patches -sorry, you missed my 'first patch' post- and to get myself exposed in the public -you missed that one too-. Don't worry, it is all neatly included in a very nice page at the haskell wiki.

That last part is actually interesting. If you don't mind, since it took me a few minutes to compose it, I am going to call the holy powers of reuse and paste a nice info bit about the closure viewer from there.

Currently it provides two new commands under ghci, :print and :sprint, both used in the same way as :type or :info. The latter prints a semievaluated closure using underscores to represent suspended computations (pretty much as [[Hood]] does). The former one in addition binds these thunks to variable names, so that you can do things with them.

Example:

Prelude> let li = map Just [1..5]
Prelude> length li
5
Prelude> :sp li
li - _:_:_:_:_:[]

Prelude> head li
Just 1

Prelude> :sp li
li - Just 1:_:_:_:_:[]

Prelude> last li
Just 5

Prelude> :sp li
li - Just 1:_:_:_:Just 5:[]

Prelude> :p li
li - Just 1 : (_t987::Maybe Integer) : (_t988::Maybe Integer) : (_t989::Maybe Integer) : [Just 5]

Prelude> _t987 `seq` ()

Prelude> :p li
li - Just 1 : Just 2 : (_t457::Maybe Integer) : (_t458::Maybe Integer) : [Just 5]

Prelude> _t988
Just 3


Its best feature is that it can work without type information, so you can display polymorphic objects the type of which you don't know. However if there is type information available, it is used. It could be made totally independent of type info, so that it could work with opaque or coerced (wrong) types. For instance:


data Opaque = forall a. O a



*Test2> let li = map Just [1..5]
*Test2> let o = O li
*Test2> head li `seq` ()
*Test2> length li `seq` ()
*Test2> :p o
o - O Just 1 : (_t126::a) : (_t125::a) : (_t124::a) : (_t123::a) : []


In the example above the li inside o is not typed, so the bindings aren't either. However, it would be possible to extend the closure viewer so that it recovers its types.

Other currently proposed extensions are a safeCoerce function (not so useful, it depends on ghc-api) and an unsafeDeepSeq (this one is decoupled from ghc-api). There is also a generally useful (for compiler/tool developers) isFullyEvaluated query function. The signatures being:


isFullyEvaluated :: a -> IO Bool
unsafeDeepSeq :: a -> b -> b
safeCoerce :: GHC.Session -> a -> Maybe b


That's all for this one. Some of you people have been annoyed that my feeds are not working. Don't worry, I will be fixing them soon.

Saturday, June 10, 2006

Short Update

In the style of a fellow Summer Haskeller I enumerate below my current headache sources.
  • C-- I got two prim ops implemented in GHC, one is for retrieving the info table pointer of a closure and another to retrieve the payload. All in all, C-- coding withouth knowing C--
  • Dealing with Pointers I've been reading the code from FPS to get a better idea of how to work with this kind of stuff. The payload of a closure is retrieved as a tuple consisting of an array of pointers (to other closures) and a bytearray. Skimming through the FPS code (now called Data.ByteString) helped me a lot and now I got the bytearray side of the tuple sorted.
  • Debugging the beast Maybe in an exercise of naivety, I hoped to be able to complete the project withouth resorting to gdb. After all, it debugging the beast is well known to be scary. The current situation is that if well the bytearray thing is working, I cannot say the same about the array of closure pointers. All I got for now are segfaults and no clue.

If you want to know a bit more about what exactly I am working on, follow this discussion in the Glasgow Haskell Mailing List.

On a side note, Simon Marlow has set up a Darcs repository at darcs.haskell.org for the nine of us. I haven't still given it a thought, but probably I will have to branch the entire GHC repo in there. I'm not sure if that's the right thing to do.