Hello Haskell
We will ease into Haskell by comparing it to our trusty steed OCaml. You might ask “why are we bothering to learn another functional language?”If your question is more like “why functional programming at all?” you might want to watch John Hughes’ talk on the subject, or read his famous paper “Why Functional Programming Matters.” First, let me admit that I love OCaml. It’s a great language, but Haskell is more widely used and is endowed with many useful features. This is a double-edged sword. For example, Haskell’s more advanced type system yields type errors that are much more difficult to understand than OCaml’s. But, we will find the language’s complexity allows us to write simple and elegant code. Programs that could not have been written as nicely in OCaml.N.b., other opinions exist, but this is mine.
I will freely admit, this is the most dull lecture of the semester. However, we have to start somewhere. It’ll get better next week. I promise.
Installing and Running
All you’ll need is a text editor and a Haskell compiler. The most commonly used compiler is GHC, the Glasgow Haskell Compiler. You can install this, and other useful tools, with the Haskell Platform. Put the following code in hello.hs
.
main = putStrLn "Hello Haskell"
Running ghc hello.hs
will produce an executable a.out
file. Running this will yield “Hello Haskell” as expected. Haskell also has a top-level interface called ghci
. Enter the following in GHCi:
putStrLn "Hello Haskell"
This should print “Hello Haskell” as before. You can load a Haskell file from within GHCi by using the :l myfile
command. This will load function definitions from myfile.hs
. You can quit GHCi with :q
.
Comparing OCaml and Haskell
Let’s see some code. On the left I will put a simple OCaml fragment and on the right a corresponding Haskell implementation. Take note of the similarities and differences.
OCaml | Haskell |
---|---|
(* A single line comment. *) (* A multiple line comment. Can say even more. *) | -- A single line comment. {- A multiple line comment. Can say even more. -} |
1
| 1
|
1 + 1 | 1 + 1 |
true
| True
|
not false | not False |
1 = 1 | 1 == 1 |
1 <> 1 | 1 /= 1 |
"Hello " ^ "world" | "Hello " ++ "world" |
[1; 2; 3; 4] | [1, 2, 3, 4] |
[1; 2] @ [3; 4] | [1, 2] ++ [3, 4] |
1 :: [2; 3; 4] | 1 : [2, 3, 4] |
('a', 1) | ('a', 1) |
let add x y = x + y | add x y = x + y |
if 1 = 1 then 2 else 3 | if 1 == 1 then 2 else 3 |
let calculate x = let a = x * 2 in let b = x - 1 in a * b | calculate x = let a = x * 2 b = x - 1 in a * b |
let rec fib n = if n == 1 || n == 2 then n else fib (n - 1) + fib (n - 2) | fib 1 = 1 fib 2 = 2 fib x = fib (x - 1) + fib (x - 2) |
let rec my_map f xs = match xs with | [] -> [] | x :: xt -> (f x) :: (my_map f xt) my_map (fun x -> x * 2) [1; 2; 3] | myMap _ [] = [] myMap f (x : xt) = (f x) : (myMap f xt) myMap (\x -> x * 2) [1, 2, 3] |
let rec my_fold_left f acc xs = match xs with | [] -> acc | x :: xt -> my_fold_left f (f acc x) xt | myFoldLeft f acc xs = case xs of [] -> acc x : xt -> myFoldLeft f (f acc x) xt |
type currency = | USD of float | Euro of float | data Currency = USD Float | Euro Float |
What did you notice? Here are a couple of interesting points.
In OCaml the string concatenation operator is
^
while the list appending operator is@
. However, in Haskell they’re both++
. Not because it’s overloaded, but because in Haskell theString
type is actually just an alias for a list of characters. Hence, you can use any list operator on a string. Predict what the following snippet will do, then try it.map (\_ -> 'a') "hello"
Haskell, like OCaml, supports pattern matching in function parameters. However, Haskell takes this a step further, allowing separate function bodies for different patterns. This is the usual style. In OCaml you either need to use conditionals or a match expression. If you want a match-like expression in Haskell, use the
case
.If you want multiple local bindings in OCaml, you need to use that many instances of
let
. Not so in Haskell. You should be aware that there also exists another syntax for local binding, thewhere
expression. I actually prefer this way.calculate x = a * b where a = x * 2 b = x - 1
These are just some highlights, there are plenty more differences you’ll come across in due time.
Getting Help
Let’s say you have a question about a Haskell function. Maybe you’ve forgotten the order of arguments to one of the fold
functions.Yes, it’s a different argument order from OCaml. Yes, it’s infuriating. Your best resource is probably Hoogle, the documentation search engine.
For more general questions, consult some of the additional reading.
Additional Reading
Here are a couple of good references for basic Haskell. I still consult with these regularly to refresh myself on syntax.
Learn You A Haskell for Great Good! is a wonderful introduction to Haskell.It holds a special place in my heart because it was the first book I ever read on functional programming. The most relevant chapters, corresponding to subjects you’re mostly familiar with from OCaml, are 2, 4, 5, and 6. I would recommend this as your first resource for learning Haskell.
You may find Niki Vazou’s lecture on Haskell 101 useful. It provides a brisk overview of Haskell basics.
Another, more extensive reference, is Real World Haskell. It goes through many practical applications, but the Haskell basics are mostly contained in 2, 3, and 4.
A classic Haskell text is Programming in Haskell, however it isn’t freely available online.