I picked up Real World Haskell last week when Gilad Bracha warned me that I might become unemployable if I don't brush up on my functional programming skills. I found his comment amusing because I have Lisp on my resume and have always wondered if anybody cared that I know Lisp. Know is an exaggeration; all I remember is cons, car, cdr and thinking why the f*** are there so many parentheses. Yet here I am, a decade older, reading up on lambda-calculus and folding to remain marketable.
One thing that might confuse the imperative programmer when reading Haskell code for the first time is the unfamiliar function definitions. In Java if you have an "add" method that adds two ints and returns an int you might write it as
add (int, int) : int
or
int add (int a, int b)
or
(int, int) -> int
In any case it's clear that add takes two ints and returns an int. But in Haskell your add function will be
add :: Int -> Int -> Int
You might guess that the first int is the first argument, the second int is the second argument, and the final int the return type. But not really. In Haskell all functions are single argument functions. Add is a function that takes an int, returns a function that takes an int, returns a function that evaluates to an int. Here's an example with the map function.
map abs [-1,-3,4,-12]
[1,3,4,12]
:type map
map :: (a -> b) -> [a] -> [b]
It appears that the map function takes two arguments, a mapping function (in this case the abs function that returns the absolute value of a number) and a list, and applies the mapping function to each element of the list. But as you can see in the type definition map is a function that takes a mapping function (a->b), returns a function that takes a list [a], returns a function that evaluates to a list [b].
This is because the lambda-calculus which Haskell is based upon doesn't have built-in support for multi-argument functions. It'd be pretty easy to support multi-argument functions according to Benjamin Pierce, but to confuse us imperative programmers they decided it would be easier and better to use higher-order functions (functions that accept and/or return functions). Instead of f = λ(x,y).s we have f = λx.λy.s. Then we would just write f v w and do two "reductions" instead of writing something like f(v,w).
Converting multi-argument functions into higher-order functions is called "currying" after Haskell Curry, for whom the Haskell language is named. Haskell was a contemporary of Alonzo Church, who developed the lambda-calculus during the 1920s. While at Princeton Church supervised the doctoral thesis of Alan Turing, the tape machine guy, who committed suicide in 1954 after being prosecuted for his homosexuality. (That was for all the history buffs out there.)
Once you see it a few times the notation becomes "normal". It's actually very elegant (among other things). Everything is a single argument function. I mean everything. You know how Smalltalk guys are always saying everything is an object, well the lambda ultimate guys say everything is a function, including numbers like 23 and 17. Maybe that's what Java's missing, a pithy tag line. Java, where everything is a....













kludge?
Posted by: Kit | July 14, 2009 at 01:36 AM
PITA?
Posted by: Acronym | July 14, 2009 at 08:54 AM
Disaster.
Posted by: N P | November 16, 2009 at 08:21 PM
Readability and maintainability are the most important.
How does Functional language address this?
Posted by: BK | January 03, 2010 at 09:33 AM