Slashdot videos: Now with more Slashdot!

View

Discuss

Share

We've improved Slashdot's video section; now you can view our video interviews, product close-ups and site visits with all the usual Slashdot options to comment, share, etc. No more walled garden! It's a work in progress -- we hope you'll check it out (Learn more about the recent updates).

The Haskell School of Expression: Learning Functional Programming through Multimedia

author

Paul Hudak

pages

363

publisher

Cambridge University Press

rating

9

reviewer

Isaac Jones

ISBN

0521644089

summary

Learn to program in a functional style in Haskell by implementing graphics, music, and robots simulations.

tester data

As the title implies, The Haskell School of Expression introduces functional
programming through the Haskell programming language and through the use of graphics and music. It serves as an effective introduction to both the language and the concepts behind functional programming. This text was published in 2000, but since Haskell 98 is the current
standard, this is still a very relevant book.

Haskell's standardization process gives us a window into two different facets of the community: Haskell is designed to be both a stable, standardized language (called Haskell 98), and a platform for experimentation in cutting-edge programming language research. So
though we have a standard from 1998, the implementations (both compilers and interpreters) are continually evolving to implement new,
experimental features which may or may not make it into the next standard.

For instance, the Glasgow
Haskell Compiler has implemented a meta-programming environment
called Template Haskell. Haskell is also easy to extend in directions that don't change the
language itself, through the use of Embedded Domain-Specific
Languages (EDSLs)
such as WASH
for web authoring, Parsec for parsing,
and Dance
(more of Paul Hudak's work) for controlling humanoid robots.

Before we get too far, I should offer a disclaimer: The Haskell
community is rather small, and if you scour the net, you may find
conversations between myself and Paul Hudak or folks in his research
group, since I use some of their software. That said, I don't work
directly with Hudak or his research group.

In fact, the small size of the Haskell community is a useful feature. It
is very easy to get involved, and folks are always willing to help
newbies learn, since we love sharing what we know. You may even find
that if you post a question about an exercise in The Haskell School of Expression , you'll get a reply from the author himself.

I consider this book to be written in a "tutorial" style. It walks
the reader through the building of applications, but doesn't skimp on
the concepts (indeed, the chapters are meant to alternate between
"concepts" and "applications"). In some ways, the code examples make
it a little difficult to jump around, since you are expected to build
upon previous code. The web site provides code, however, so you can
always grab that and use it to fill in the missing pieces.

For readers who wish to use this book as a tutorial, and to
implement all of the examples (which is highly recommended), I suggest
that you grab
the Hugs interpreter and
read the User's
Guide while you're reading the first few chapters of
The Haskell School of Expression. Hugs is very portable, free, and easy to use. It
also has an interface with Emacs.
Unfortunately, some of the example code has suffered from bit-rot, and
certain things don't work out-of-the-box for X11-based systems. The
bit-rot can be solved by using the "November 2002" version of Hugs.
This is all explained on SOE's web page.

The Haskell School of Expression should be very
effective for programmers who have experience in more traditional
languages, and programmers with a Lisp background can probably move
quickly through some of the early material. If you've never learned a
functional language, I highly recommend Haskell: Since Haskell is
purely functional (unlike Lisp), it will more or less prevent
you from "cheating" by reverting to a non-functional style. In fact,
if you've never really looked at functional programming languages, it
may surprise you to learn that Haskell has no looping constructs or
destructive assignment (that is, no x = x + 1). All of the tasks
that you would accomplish through the use of loops are accomplished
instead through recursion, or through higher-level abstractions upon
recursion.

Since I was already comfortable with recursion when I started this
book, it is hard for me to gauge how a reader who has never
encountered recursion would find this book's explanation of the concept. The Haskell School of Expression
introduces recursion early on, in section 1.4. It is used in examples
throughout the book, and if you follow along with these examples, you
will most certainly be using it a lot. The introduction seems natural
enough to me, but I note that Hudak does not give the reader any extra
insight or tricks to help them along. Not to worry, though; recursion
is very natural in Haskell and the reader may not even notice that
they are doing something a little tricky.

The use of multimedia was a lot of fun for me, and should quickly
dispel the myth that IO is difficult in Haskell. For instance, Hudak
has the reader drawing fractals by page 44, and throughout the book,
the reader will be drawing shapes, playing music, and controlling
animated robots.

Any book on Haskell must be appraised for its explanation of
monads in general and IO specifically. Monads are a purely
functional way to elegantly carry state across several computations
(rather than passing state explicitly as a parameter to each
function). They are a common stumbling block in learning Haskell,
though in my opinion, their difficulty is over-hyped.

Since input and output cause side-effects, they are not purely
functional, and don't fit nicely into a function-call and recursion
structure. Haskell has therefore evolved a way to deal safely and
logically with IO through the use of monads, which encapsulate mutable
state. In order to perform IO in Haskell, one must use monads, but
not necessarily understand them.

Some people find monads confusing; I've even heard a joke that you
need a Ph.D. in computer science in order to perform IO in Haskell.
This is clearly not true, and this book takes an approach which I
whole-heartedly agree with. It gets the reader using monads and IO in
chapter 3 without explaining them deeply until chapters 16 (IO) and 18
(monads). By the time you get there, if you have heard that monads
are confusing, you might be inclined to say "how is this different
from what we've been doing all along?" Over all, I was pleased with
the explanation of monads, especially state monads in chapter
18, but I felt that the reader is not given enough exercises where
they implement their own monads.

If you're worried that drawing shapes and playing music will not
appeal to your mathematic side, you will be pleased by the focus on
algebraic reasoning for shapes (section 8.3) and music (section 21.2),
and a chapter on proof by induction (chapter 11).

After reading this book you will be prepared to take either of the
two paths that Haskell is designed for: You can start writing useful and elegant tools,
or you can dig into the fascinating programming language research
going on. You will be prepared to approach arrows, a newer
addition to Haskell which, like monads, have a deep relationship to
category theory. Arrows
are used extensively in some of the Yale Haskell group's recent work.
You will see a lot of shared concepts between the animation in
The Haskell School of Expression and Yale's "Functional
Reactive Programming" framework, Yampa. If you like little languages,
you'll appreciate how useful Haskell is for embedded domain-specific
languages. It may
be even more useful now that Template Haskell is in the
works. Andrew
Cooke described Purely Functional Data Structures as
a great second book on functional programming. In my opinion,
The Haskell School of Expression is the great first book
you're looking for.

I haven't got the exact figures, but I reckon 99% of all code written out there must be written in Imperative (sometimes pseudo OO) languages. There must be SOME reason functional languages are not so popular.

Functional language are only good in theory. Sure, you can easily write programs in them, but they abstract over how the program is executed. And the programs are going to be executed in an imperative manner; machine code is imperative, remember?

Thus, there's a MASSIVE performance loss when a functional programming language is executed on any of the existing processors. Because the compilers can't think and optimise the code to best fit the imperative model. Where as the human being s can. That's why we should stick to imperative programming languages.

The day someone actually invents a function processor, we could start promoting these fringe langauges. Till then, let's keep Haskell as part of CS811

way back when in college, the most interesting thing was that the program couldn't do I/O during the execution, only as an exit value. That makes useful daily programs difficult to write in a 'purely functional' language. The review talks about monads being a solution, but I can't see that putting something on the screen our worse a printer is something that can be undone. Therefore, I/O must be a side-effect, so how can a real 'purely functional' language like haskel do I/O?

I think that there is a problem with newer programmers going into a language such as say, java, or C#. When i learned programming i learned C++ in ms-dos. We wrote our own string classes, used pointers, learned ADT's like, linked lists, and binary trees. Nowadays in java you write a program and use everyone elses stuff. there is a linked list class in Miscrosoft's.NET framework. Nothing is ever written from scratch anymore. IMHO you cant learn actual programming without getting into the nitty gritty your self.

Do people think it's a good thing for a C++/Java/.NET programmer to go back to the drawing board for a few months and learn stuff like functional programming? I thought about coming up with a syllabus for myself of C, Haskell, LISP and Perl (which just evades me....)

Herein lies the rub in getting adoption of any of the more "esoteric" (read: not procedural) languages into the mainstream: libraries that require "understanding" of the functional model. After spending years interviewing programmers I can safely say that most barely remember the functional languages they were taught (if they were taught). Try to then force them to use an "alien" library that works in a functional way, and you might as well ask them to chop their arms off and thresh wheat.

I sometimes suspect that.NET may be the only hope of getting functional programming adopted by the maininstream. Currently the CLI has limitations that hamstring functional languages, but Microsoft has actually been bothering to try to rectify those problems. If they do, I would *love* to run ocaml or Haskell with the.NET infrastructure to back up the boring routine work. For that matter *any* major libarary of functionality accessable to a functional language.

I think that this choice of approaches to programming is similar to the choice in electrical engineering between solving problems in the time domain vs. frequency domain.

To me, functional programming is similar to the frequency domain. There are certain problems that are almost impossible to solve in the time domain that are trivial to solve in the frequency domain. However, the frequency domain is harder to understand, and the real universe actually operates in the time domain. Moreover, some problems that are trivial in the time domain blow up when analyzed in the frequency domain.

There few if any EEs who would advocate discarding all time domain calculations in favor of the alternative. That also applies to tools; few people would throw away their oscilliscopes just because they have a spectrum analyzer available.

That's what bothers me about "pure" languages of any form. You're intentionally throwing away some of the available tools to prove a point.

Sometimes a functional approach can provide an extremely powerful way to solve a problem with a tiny amount of code. However, sometimes another part of the same program would be better done in a more mundane fashion. The functional style's tendency to make you think about every problem "inside out" and to make you solve every problem in a "clever" way can get to be grating. I like to keep the option to use each style as needed, so I prefer languages that support features from a variety of programming styles.

yes, this is a real problem. I've spoken w/ some of the implementors, and they really thought that strictness analysis would get them a whole lot more.

Lazyness sucks not so much for speed (but this is indeed an issue), but for interacting with foreign functions, and mostly because it breaks tail-recursion. You don't often notice, because haskellers tend to use programming idioms which don't rely solely on tail-recursion.

It also makes predicting the performace of your program almost impossible. Chris Okasaki mentions that most lazy programs are analysed as if they were strict.

A second, smaller problem is that haskellers are really smart. really really smart. This makes easily approachable texts pretty thin on the ground. Two sentences in, you're being bombarded by catamorphisms, anamorphisms, and monoids.

"Furthermore, malloc is fairly expensive, so programmers often malloc a single large chunk of store, and then allocate "by hand" out of this."

I've seen this type of statement elsewhere in defense of non-C languages. And yet I've very rarely seen this done in code that wasn't either in 1) an embedded system or 2) a device driver or kernel module.

In those cases where I have seen this in application code, it has been accompanied by lots of other newbie gaffes. I'd question the sanity of anyone who thinks that a user-level app will benefit from a hand-coded heap manager.

But perhaps there are exceptions...does anyone actually do this routinely?

MSDN Academic Alliance [msdnaa.net] has some articles on progress being made on using functional languages on the CLI. Microsoft seems to be aware that there is value here, but they are moving cautiously.

One interesting point on the haskell website was that SQL is almost a functional language.
I, for one, do all kinds of wild data gymnastics in SQL, and wonder if more could be done to 'get people in the door' with SQL DML statements as a lead-in.
Always wanted to do more with functional programming, wondering if EMACS Lisp might prove more immediately fruitful...

Playing with F#, the entire library is accessable. Obviously, in some ways using these libraries funnels those sections of the program into a more procedural mind set, but other sections work very well.

C# and F# interop [microsoft.com] has a link on how to call C# from F#. However, it is interesting that F# uses some of the OCaml library [microsoft.com] *in addition* to the.NET libraries, as obviously OCaml has functionality specifically for manipulating functional structures, which is still valuable for F# programmers.

SQL is a declarative language, which is probably why it feels functional. Declarative languages allow the user to specify *what* you want, and then the underlying engine determines *how* to get it. SQL in some ways is closer to PROLOG, which is a declarative logic language (in fact, it is trivial to create SQL like queries in PROLOG).

Functional languages can implement declarative syntaxes easily, but the real defining factor is that functions are "first order" objects, which can be applied, manipulated and passed. Frankly, if SQL had first order functions, many wild data gymnastics would be vastly simpler. I grumble at the lack of code reuse in SQL (and I say that as a big fan of the ease of use of SQL on the whole). For example, in SQL I must repeat my subquery every time I wish to apply it.(1) Calculations must be specified both in the select list and the conditional if they are used in both places, instead of being defined once and the results being available (some SQL dialects have workarounds for this). Recursion is right out (a hallmark of functional languages is heavy use of recursive functions) which makes navigating tree structures a total bear (PSQL has extensions for trees, but not very clean ones).

Perhaps future developments that bring SQL closer to the true relational model (which has deep roots in set theory) which would make it possible to bring it closer to a true functional language as well. I think SQL would benefit wildly from the ability to define common structures (functions) and yet be able to apply the optimizer to the end result.

(1) Footnote: T-SQL has "user defined functions", but the impose a nasty overhead because they are not part of the query optimization process.