Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Sunday, June 08, 2008

Real World Haskell

When I'm in the mood to feel really dense, I try to wrap my brain around functional programming. My poison of choice is Haskell, since that's the purest and least compromising of the languages, in my uninformed opinion. I have a couple of books on the subject and every once and a while I struggle with the syntax and the alternate mode of thought.

I recently stumbled across a very approachable on-line book-in-progress about Haskell: Real World Haskell.

I still have my doubts about functional programming; I should love it, because I tend to think about code and how code fits together all the time. However, the heavy mathematical bent of functional programming is a bit of a challenge, and the FP-ers seem to value conciseness over all other things. I worry that Haskell programs are write-only in the way that Perl can be; that every program is an elegant puzzle-box, but a puzzle nonetheless.

I'm still intrigued not due to the conciseness, or the promise of parallel execution, but because of lazyness. Having lazy evaluation built right into the language means that a lot of common coding conventions and patterns are simply a natural byproduct of the use of the language.

For example, throughout Tapsestry there are examples of code that is based on a recursive algorithm implemented non-recursively (typically, using queues). In Haskell, you get that for free pretty much universally: the Haskell execution stack does not get very deep, though there's a kind of stack of as-yet-unevaluated expressions (it looks like the Haskell folk call these "thunks") behind the scenes, acting like the queues I'm coding directly.

Because it's baked into the language, you are free to express algorithms very purely, without the implementations being obscured by performance details (such as converting recursion into queues). In fact, the laziness of Haskell is really good at handling infinite lists (as long as you don't ask for the length of that list!)

There's a bit of hype going on in the FP/Haskell/Erlang space. For example, people keep talking a lot about the need for FP to tackle large numbers of cores. Does the Emperor have any clothes here? I'm not certain: Haskell and Erlang use non-native threads. That's a great way to maximize a single core and all the no-sideffects, no-mutable state simplifies the problem vastly from a typical Java application.

However, Erlang typically approaches the highly scalable space by starting (and, as necessary, restarting) lots of processes. The immutable state must be extracted from one process and serialized to another; Erlang has a native format for this that's pretty efficient. Haskell adds similar functionality as an add-on library. But from my point of view, it doesn't feel that different from JMS and messaging with a bit of coding discipline.

In fact, the point of view of 1060 NetKernel is that you can have the advantages of an Erlang style model, but implement it in your choice of languages (Java, JavaScript, Python, etc., etc.). We may have a gig at Formos where I'll have a chance to really look into NetKernel, I've been hovering around the edges on it for a couple of years.

6 comments:

Bill Holloway said...

FP can be very terse and write-only as you say. And different programmers on a team have different styles with it, making the situation potentially worse.

Personally, I'm much more excited about Groovy-Tapestry. Grapestry 5? I mentioned that to our developers and ears perked up. Enough of us know enough about Groovy to feel a production advantage with it over Java.

Howard said...

I'm continuing to code a full Blogger app in all Groovy and liking it. Closures are great for me; I already write code as clouds of tiny objects, closures are just the language helping me do that easily.

Bill Holloway said...

Closures are one of the reasons that I WON'T spend much time now in Smalltalk. I'll get too hooked in to how awesome they are and want to drop Java! I want to get groovy going at our biz. I hope the performance remains high with the extra stacks of calls needed in groovy.

Chrigel said...

@bill

Funny you mention the name Grapestry. It has been called already, but in the context of beeing a Grails plugin which would allow to use Tapestry as view technology (a similar grails plugin exists for Wicket).

I personally prefer the approach to use Groovy as "top-layer" to T5. Very keen to hear more about this ...

TuringTest said...

Correction: The current ghc version 6.8 spreads Haskell threads across a configurable number of real os-threads.

James Iry said...

Howard,

Haskell is a beautiful language, and quite mind-bending to those of us who started in the C/C++/Java/etc world. I can't recommend it highly enough as a learning exercise if nothing else.

I think things like HAppS should show that it's good for far more than "mathematical" applications or pure brain stretching.

As for readability - this may be a eye of the beholder thing. It's quite easy to write unreadable Java, too. And, in the large, stateful, side effecting code can tend to create spaghetti-like temporal coupling in even the best, most modular, code

But the main reason I'm writing this is that I wanted to mention that if you are looking at JVM languages, Scala has support for optional laziness. By default Scala uses the more conventional strict evaluation model, but it has an annotation for call-by-name and an indirect encoding for call-by-need (which is Haskell's default evaluation strategy). Many of the data structures in Scala's standard library are lazy or partially lazy.

Finally, to make an entirely pedantic point that's totally irrelevant to what you were talking about, Haskell isn't really the most pure of languages. But the more pure languages are even less well known than Haskell. :-)