« Solving Cryptograms, Part 2Solving Cryptograms, Part 1 »

Two weeks of Haskell

25/09/08

Permalink 08:48:13 pm, 580 words
Categories: Code

Two weeks of Haskell

So I’ve done about two weeks of real work in Haskell. Here are some observations.


  1. I got used to typed programming pretty fast. For the first week the compiler beat me about the ears every time I reloaded. Now I cringe in anticipation and am slightly surprised when my code type checks with no problems. I made a few small adjustments to my working habits, but nothing major.
  2. The REPL is more primitive than the Lisp and Python REPLs I’ve used. You have to load a whole file at a time, and the whole state of your program resets. This is a “best practise” for REPLs according to the PLT, but one that is mildly inconvenient. Ad-hoc reloading only bit me about once a month, and the consequences were never that bad.
  3. Convenient currying and composition are the number-one contributor to brevity. This is probably because I haven’t fully shifted from my Scheme/Python mindset. But Scheme and Python programs do look a little muddier than they used to because of all their nested function calls. I haven’t quite developed the (apparent) Haskellish aversion to parentheses or they might look a *lot* muddier.
  4. Speaking of ($) (used to avoid parentheses), I still don’t know if I like all the funky operators in Haskell. It’s no C++, where a + could mean anything*. But there is a lot of @@#$*@!! going on. I’ve defined a couple of operators on my own and I still don’t know if it was a good idea. My excuse is that the paper whose code I was implementing overloaded (-) in its math notation, but of course you can’t do that in Haskell. So I decided to call it (\\\) because it removes certain information from a list, like the built-in (\\). It’s a cool paper [PDF], though, even with its overloaded (-).
  5. I still haven’t figured out debugging. My solution so far has been to promote the expression where I *think* the bug is to a standalone function and feed it input that I think it should be getting. I need to learn how to trace functions or something. But…all those people who claim that their program is usually bug-free when they finally get it past the Haskell compiler? I’m not saying they’re lying, just that they’re former C programmers**.
  6. The compiler error messages would be 10 times easier on newbies if the compiler could reliably identify cases where a function is given the wrong number of arguments. Because of currying, I guess, it is never quite certain and so the message is on the third line with the disclaimer “Probable Cause: wrong number of arguments".
  7. OR
    Haskell needs to grow a magical refactorer like the Popular Languages have. One that works with Emacs, and one that detects when I add an argument to a function. There is one called Hare at version 0.4, but it has a big disclaimer in the README that scared me off after my lukewarm (at best) experience with Bicycle Repair Man for Emacs.
  8. Text processing works pretty well. I’m not quite as facile as I am with Python yet since I haven’t learned all the text manipulation functions. Manipulation of data at the REPL isn’t quite as nice because there are no dictionary literals, so getting other code to spit out strings containing readable dictionaries is just a tad more complicated.

*Or worse: Everything. Whoa.
**OK, they’re lying. Well, actually, allow me to waffle a bit. Programs that get past the compiler are bug-freer. But not bug-free.

12 comments

Comment from: Rose [Visitor] Email
Ummm...where's the rest of your post?
26/09/08 @ 00:22
Comment from: Fletch [Visitor] Email
Hi,

I've just finished a couple of weeks of Haskell and my experience was similar especially for points 5, 6 and 7.

Haskell takes away both a debugger and a way to conveniently add debugging statements (SIDE EFFECTS!!!). I'm pretty sure it's something that'll go away with time but I spent a lot of time quite confused...

I totally agree with the refactoring comment. I have an irrational fear of changing a method signature in Haskell now, which I'm sure can't be a good thing...
26/09/08 @ 04:26
Comment from: Fletch [Visitor] Email
I thought I'd add that it's also the most fun that I've had coding for a very long time.
26/09/08 @ 04:27
Comment from: Eugene Kirpichov [Visitor] Email
> and a way to conveniently add debugging statements (SIDE EFFECTS!!!).

What about Debug.Trace? http://cvs.haskell.org/Hugs/pages/libraries/base/Debug-Trace.html
26/09/08 @ 05:48
Comment from: Fletch [Visitor] Email
Dang it all to heck. I knew I should have turned to the internet for help sooner. This is why I can't have nice things.

I was going through the "Real World Haskell" book and it doesn't mention Debug.trace.

Thanks for the tip!
26/09/08 @ 07:11
Comment from: sandersn [Member]
@Eugene:
What I want is a way to conveniently and methodically add debugging statements, like trace in Lisp. I suppose it might be buildable from Debug.trace, though.

There *are* debugging solutions that I've heard about, though, so it's just a matter of hitting a bug bad enough to force me to learn one.

@Fletch
I have an irrational fear of method signatures, period. :)
26/09/08 @ 07:35
Comment from: Adrian Quark [Visitor] Email
GHC has a built-in debugger:

http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-debugger.html

It's not as nice as Hat (the Haskell tracer) but much easier to get started with. On the other hand, the lazy evaluation makes it kind of confusing, so it takes some practice before you learn to interpret the results.
26/09/08 @ 10:24
Comment from: pj [Visitor]
your home grown solution to (5) is a good practice anyways (promoting code to easily testable functions) right?
05/10/08 @ 10:33
Comment from: rieux [Visitor] Email · http://www.ccs.neu.edu/home/tov/
I think it's great that you're trying this. Some of the things you point out, such as bad error messages, really ought to be getting more attention than they seem to be. Others, as you accurately point out, may merely indicate your inexperience in this kind of language.

It's funny, but after six years of programming in Haskell, I don't think I ever miss a debugger. Sometimes, as you do, I refactor until I can see what particular functions are doing, but just as often I merely read the code very carefully until I see what the problem is. Sometimes it seems like debuggers encourage the programming to think operationally when thinking mathematically would be more productive in the long run.
05/10/08 @ 18:58
Comment from: Thomas Hartman [Visitor] Email · http://www.happstutorial.com
Debugging, agree with above comments.

I tend not to use the ghci interactive debugger that much.

I depend on Debug.Trace.trace (a standard library function which sneaks IO in anywhere you have a showable value), which I augmented with some helper functions (in Misc.hs).

traceTrue x = trace (show x ++ "\n\n") True
traceIt x = trace (show x ++ "\n\n") x
traceMsg msg x = trace ( "\n\n" ++ msg ++ (show x) ++ "\n\n") x

Typical (basically only) use of traceTrue: view arguments to a function in stdout, by putting it on the right side of the "execute this branch if true" bar in a function definition. The function executes as it normally would, because traceTrue always returns true. But you get debugging info as a side effect.

tutlayout (RenderGlobals ts mbU) attrs tmpl0 | traceTrue ((RenderGlobals ts mbU), attrs, tmpl0) = .....

Typical use of traceIt: quickie print to stdout of some var or expression:

mainUserMenu = if (isJust mbU)
then traceIt $ paintHMenu .
map (menuLink ts ("/tutorial/" ++ tmpl0) )
. readtut $ "mainusermenu"
else ""

traceMsg does pretty much the same thing as traceIt, except you preface the shown expression with your own message like "show the menu: ". This can be useful if you are doing more than one trace and need to disginguish them.

The formatting in the above is messed up due ot the paste, sorry.
06/10/08 @ 06:59
Comment from: pj [Visitor]
@Thomas
Cool. I didn't know you do 'printf' without changing the signature of the function!
That pretty much changes it for me.

'printf' is all the debugging tool anyone will ever need :-)
06/10/08 @ 12:29
Comment from: Chris Done [Visitor] Email · http://chrisdone.com/
It is my belief that Haskell newbies (from (inevitably) imperative languages), including myself, come to Haskell and are used to printing things out to debug their code. They are all directed to Debug.Trace. It's the old printf-style. Later they stop using it. You write your function, test it in GHCi, compile it and start using it. I seriously class Debug.Trace as a phase that newbies go through (see it all the time on the #haskell IRC channel).
12/10/08 @ 07:15

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)

Nathan Sanders : Journal

powered by b2evolution