CS223, 4/12/2010 Lecture 7 Elementary Haskell I 0. introduce self Welcome to the introductory Haskell lecture. I refrain from presenting "Hello World" in Haskell as it is an advanced topic. 1. how many people are seasoned ML programmers? 2. how many people are seasoned Haskell programmers? characterize the differences between ML and Haskell please point: ML and Haskell are superficially similar, but ML and Haskell are fundamentally different A general comparison of Haskell and ML. --------------------------------------- Points of similarity between ML (SML in particular) and Haskell 1. both have first-class functions (functions are values) 2. both are statically typed 3. both have polymorphic types 4. both have algebraic datatypes (& pattern matching) 5. both have automatic type inference 6. both have "layered patterns" (as in ML, @ in Haskell) 7. both support a fairly conventional set of basic types integers, reals, booleans, strings 8. both have lists as a basic and heavily used type Differences between ML and Haskell 1. Haskell is pure, without side effects or exceptions, while ML has mutable data structures (refs and arrays) and exceptions 2. Haskell has lazy evaluation (a variant of call-by-name evaluation with memoization), while ML has strict evaluation. (ML can implement forms of lazy evaluation though libraries, but there is no special syntactic support for it.) 3. Haskell has even more special notational support for lists -- list comprehensions.XC 4. Haskell has boolean guards associated with pattern matching 5. Haskell functions are usually curried, while SML functions use tuple or record arguments for multi-argument functions 6. Haskell has type classes to support abstraction over types with associated interfaces. 7. ML uses modules and functors to support types with associated interfaces and abstraction over such. 8. Haskell uses monads to simulate imperative, effectful programming (e.g. assignable variables and I/O). ML does not need to simulate imperative programming since it supports it directly. Syntactically, there are similarities between Haskell and ML, but they differ in style. Haskell has a minimal, calculator-style syntax. ML syntax is heavier, but probably more readable, particularly for larger bodies of code. ----------------------------------------------------------------- Practical issues: 1. installing ghc and ghci (Haskell Platform) ----------------------------------------------------------------- Consider the differences between ML and Haskell in three broad categories: - superficial syntactic differences, - fancy extra syntax on Haskell's part, and - deep semantic differences with far-reaching implications. Today's lecture is concerned with the first two. Time permitting, we'll get into the juicy third category. Category 1 -- superficial differences in syntax: thing ML Haskell types int Int 'a tree Tree a 'a list [a] 'a * 'b (a,b) type ascr. x : int x :: Int cons x :: xs x : xs list append xs @ ys xs ++ ys fun. comp. f o g f . g anon. fn. fn x => x \ x -> x val val n = 1 n = 1 fun fun f x = x f x = x fun type ML ascription fun f (b:bool) : int = if b then 1 else 0 Haskell f :: Bool -> Int f b = if b then 1 else 0 case case xs case xs of of [] => 0 [] -> 0 | h::_ => h h:_ -> h let let val x = 1 let x = 1 val y = 2 y = 2 in in (x+y, x-y) (x+y, x-y) end type syn. type 'a pr = 'a * 'a type Pr a = (a,a) datatype datatype color data color = R | G | B = R | G | B ML datatype 'a tree = Lf | Nd of 'a * 'a tree * 'a tree Haskell data Tree a = Lf | Nd a (Tree a) (Tree a) comments (* comm *) -- comm to EOL {- multiline comm -} ALSO in Haskell, String means [Char], really. ALSO the fact that functions are usu. curried affects interfaces, i.e., foldr in ML is ('a * 'b -> 'b) -> 'b -> 'a list -> 'b in Haskell is (a -> b -> b) -> b -> [a] -> b ----------------------------------------------------------------------- Category 2 -- Haskell syntactic bonuses: enumeration notation [1..10] [1,4..20] [10,9..0] In ML, we can generate such integer ranges using a function: fun range (init: int, incr: int, final: int) = if incr < 0 then if init < final then [] else init :: range(init+incr, incr, final) else if init > final then [] else init :: range(init+incr, incr, final); val r1 = range(1,1,10); val r2 = range(1,3,20); val r3 = range(10,~1,0); A different function would have to be used for similar sequences of reals.