We’re going to do this real fast; for 131:
Haskell = Ocaml + Better syntax
We assume you are familiar with Ocaml
So: we’ll learn Haskell by comparison.
Type Ascription
Ocaml uses :
for type ascription
e : t
meanse
has typet
vs.
Haskell uses ::
for type ascription
e :: t
meanse
has typet
Function Definitions and Calls
Ocaml
(* val incr : int -> int *)
let incr x = x + 1
let stincr = fun x -> x + 1
let eleven = incr (10 + 2)
vs
Haskell
let
not needed for top-level binding.
Pattern Matching
Ocaml
(* val listSum : int list -> int list *)
let rec listSum xs = match xs with
| [] -> 0
| (x::xs') -> x + listSum xs'
vs
Haskell
or better,
Haskell allows different equations for different cases.
Colon vs. Double-Colon
Ocaml
- uses
::
for “cons” - uses
:
for “has type”
vs
Haskell
- uses
:
for “cons” - uses
::
for “has type”
A handy table
Operator | Ocaml | Haskell |
---|---|---|
:: |
“cons” | “has type” |
: |
“has type” | “cons” |
Local Variables
Ocaml
(* val filter : ('a -> bool) -> 'a list -> 'a list *)
let filter f xs = match xs with
| [] -> []
| x::xs' -> let rest = filter f xs' in
if f x then x :: rest else rest
vs
Haskell
filter :: (a -> Bool) -> [a] -> [a]
filter f [] = []
filter f (x:xs) let rest = filter f xs' in
if f x then x:rest else rest
QUIZ: Local Variables
What is the value of quiz
?
A. Syntax error B. Type Error C. 0
D. 1
E. Other
QUIZ: Local Variables
What is the value of quiz
?
A. Syntax error B. Type Error C. 0
D. 1
E. Other
QUIZ: Local Variables
What is the value of quiz
?
A. Syntax error B. Type Error C. 0
D. 1
E. Other
QUIZ: Local Variables
What is the value of quiz
?
A. Syntax error B. Type Error C. 0
D. 1
E. Other
Local Variables (revisited)
So we can take
filter :: (a -> Bool) -> [a] -> [a]
filter f [] = []
filter f (x:xs) let rest = filter f xs' in
if f x then x:rest else rest
and write it better as
filter :: (a -> Bool) -> [a] -> [a]
filter f [] = []
filter f (x:xs) = if f x then x:rest else rest
where
rest = filter f xs'
where lets you pull local variables aside:
- meaning exactly same as
let
, but - can specify them in any order.
(Seems strange at first, but truly beautiful.)
Anonymous Functions
Ocaml
vs
Haskell
Very similar: Ocaml’s fun
is replaced with Haskell’s \
Tuples and Lists
Ocaml
(* val partition: ('a -> bool) -> 'a list -> ('a list * 'a list) *)
let partition f xs = (filter f xs, filter (negate f) xs)
(12, “cat”)
vs
Haskell
Note
- Haskell uses
(t1, t2)
vs Ocaml’s(t1 * t2)
- Haskell uses
[t]
vs Ocaml’st list
Larger Example
Ocaml
(* val sort : 'a list -> 'a list *)
let rec sort xs = match xs with
| [] -> []
| (h::t) -> let (ls, rs) = partition (fun x -> x < h) t in
sort ls @ [h] @ sort rs
vs
Haskell
sort :: (Ord a) => [a] -> [a]
sort [] = []
sort (h:t) = sort ls ++ [h] ++ sort rs
where
(ls,rs) = partition (\x -> x < h) t
QUIZ: List Comprehensions
What is the value of
A. Syntax Error B. Type Error C. [0, 5]
D. [0, 1, 2, 3, 4]
E. [0, 1, 2, 3, 4, 5]
QUIZ: List Comprehensions
What is the value of
A. Syntax Error B. Type Error C. [0, 50]
D. [0, 10, 20, 30, 40]
E. [0, 10, 20, 30, 40, 50]
QUIZ: List Comprehensions
What is the value of
A. []
B. [0]
C. [0, 10]
D. [0, 10, 20]
E. [0, 10, 20, 30]
QUIZ: List Comprehensions
We can simplify the sort
using list comprehensions, as in Python:
sort [] = []
sort (h:t) = sort ls ++ [h] ++ sort rs
where
ls = [x | x <- t, x <= h]
rs = [x | x <- t, h < x]
Defining Data
Ocaml
vs
Haskell
Constructing Data
Ocaml
let ex0 = Number 5.
let ex1 = Plus (ex0, Number 7.)
let ex2 = Minus (Number 4., Number 2.)
let ex3 = Times (ex1, ex2)
vs
Haskell
Note
The tags Plus
, Number
etc. are (constructor) functions
QUIZ: Constructor Types
Given
What is the type of Number
?
A. Expr
B. Double
C. Double -> Expr
D. Expr -> Double
E. Expr -> Expr
Destructing (Accessing) Data
Ocaml
(* val eval: expr -> float *)
let rec eval e = match e with
| Number n -> n
| Plus (e1, e2) -> eval e1 +. eval e2
| Minus (e1, e2) -> eval e1 -. eval e2
| Times (e1, e2) -> eval e1 *. eval e2
vs
Haskell
eval :: Expr -> Double
eval (Number n) = n
eval (Plus e1 e2) = eval e1 + eval e2
eval (Minus e1 e2) = eval e1 - eval e2
eval (Times e1 e2) = eval e1 * eval e2
Oh look, we wrote a compiler!
- What’s the source language?
- What’s the target language?
Recursive Functions
Ocaml
vs.
Haskell
Printf Debugging
Very Very Important
Q: How to print out each input-output pair for calls to fact
?
Ocaml
(as in Java, C, Python…), just print it:
let fact n =
let res = if n <= 0 then 1 else n * fact (n-1) in
let _ = Printf.printf "fact n = %d, res = %d\n" n d in
res
vs
Haskell
You can’t just print stuff (for very good reasons…)
However, you can do this:
import Text.Printf (printf)
import Debug.Trace (trace)
-- trace :: String -> a -> a
fact n = trace msg res
where
msg = printf "fact n = %d, res = %d\n" n res
res = if n <= 0 then 1 else n * fact (n-1)
Which pretty much does what you want.
*Foo> fact 5
fact n = 0, res = 1
fact n = 1, res = 1
fact n = 2, res = 2
fact n = 3, res = 6
fact n = 4, res = 24
fact n = 5, res = 120
120