• Feeds

    Subscribe in a reader

  • Ads

A teeny bit of Haskell

When it comes to academic approaches to teaching Computer Science, there are three major schools of thought. You have the MIT cabal, which is Scheme-based, the CMU cabal which is all about ML and the Yale cabal, which is centered on Haskell. Northwestern is part of the MIT cabal, so most of my academic exposure to functional programing concepts came via Scheme/LISP.

Last week on a lark, I decided to see how the Haskell crowd lived. I checked out a couple books from the MS Library, downloaded a Haskell environment, and started puttering. I'm by no means a Haskell virtuoso now, but I'm getting a decent flavor of the language. At least enough to begin to see the various Haskell-isms that are popping up with increasing frequency in things like LINQ and other projects that are on my radar.

The guard syntax in Haskell is pretty nifty, especially when it comes to defining recursive functions. For example, here's factorial in Haskell:

  fact x | x == 0 = 1
         | otherwise = x * fact (x-1)

and in Scheme:

   (define (fact x)
      (if (eq? x 0 )
           1
           (* x (fact (- x 1)))))

I like the way Haskell lifts the explicit conditional into the function definition syntax.

I like the pattern matching capabilities of Haskell too:

pop [single] = single
pop [first:rest] = (first,rest)

That's a simple stack pop function defined for two cases (both of which take a single parameter, a list representing the stack). If there's only one element on the stack, we just return it. If there's more than one, return a tuple where the first element in the tuple is the one we popped off the stack and the second element in the tuple is the rest of the stack. The Haskell syntax is again more terse than the Scheme equivalent:

(define (pop stack)
     (if (eq? (cdr stack) '())
             (car stack)
          (list (car stack) (cdr stack))))

One place where Haskell wins over scheme is that Haskell has list comprehensions. List comprehensions are a way of specifying a list of items based on membership criteria, rather than populating the list items explicitly. For example, here's how you pull out the even members of some list s:

[x | x <- s, even x]

Which is basically the following LINQ-ism (I think):

from x in s
where even(x)
select x

Map in Haskell can be done in Haskell as:

map function list = [function x | x <- list]

And in quasi-LINQ as:

public static IEnumerable<TRet> Map<TArg, TRet>( Func<TArg, TRet> function, IEnumerable<TArg> list)
{
    return from x in list
           select function(x);
}

There's an example that clearly illustrates the syntactic overhead of static typic, I think. Anyway, I have much left to explore in this area.

At this point, I have two major beefs with Haskell. The first is that the syntax is almost too expressive -- there's a lot of "magic" going on under the hood sytactically, and until you internalize the magic it's hard to look at a piece of Haskell syntax and fully wrap your head around it. The second (and this may just be a function of my Haskell environment) is that the language doesn't seem to be very REPL-friendly, which gets in the way of experimentation. One of the things that I really like about Scheme is that you can just fire up a REPL and start hacking away -- that feature really lowers the barrier to entry for me.

#1 Kristjan Kannike on 8.01.2006 at 2:12 PM

You might be better off with GHC (http://haskell.org/ghc/), asits REPL, GHCi, is more friendly (you can define things on the fly as e.g. let x = 5).(And of course typing is static in Haskell as well, just that it has type inference.)

#2 Steve Maine on 8.02.2006 at 9:19 AM

Thanks Kristjan, I'll have to give GHCi a try. Good point about static typing, too...I probably should have rephrased that....