A taste of Haskell
Paul Callaghan
(not that one)
Language
Wars ?
My aim today:
Haskell isn't hard
and it's worth a go
A bit of what
the books
don't tell you
What is
Haskell?
A load of
complex stuff?
(too much maths)
An exercise
in monasticism?
Job security
for academics?
An infinite supply
of PhD topics?
Haskell is really
a language for
playing with
data
Excellent tools for
* defining new data types
* building complex data
* taking data apart
* and doing big operations on it
Many ways to create types
Lists, Tuples/Records all built in
Adding other new data types is easy
data Port = Number Int | Name String
data TreeA = NodeA (Int,Bool) [TreeA]
Easy to generalise types
data TreeB a = NodeB a [TreeB a]
type TreeA = TreeB (Int,Bool)
Very powerful data types...
data TreeC c a = NodeC a (c (TreeC c a))
type TreeB a = TreeC [] a
type TreeD a = TreeC (Day ->) a
So, a very rich and convenient
'(sub)language' for data types
* more precise about types you want
* less work to add types you need
Constructing data
* syntactically clean language
* few type annotations needed
* powerful overloading support
t1 = NodeB "b" [ NodeB "a" []
, NodeB "c" []
, NodeB "d" []
]
t2 = NodeB "b"
[ NodeB s []
| s <- ["a", "c", "d"] ]
Taking data apart
"Pattern matching" is a
mix of testing and extraction
leftChild (NodeB _ [])
= Nothing
leftChild (NodeB _ (NodeB x _:_))
= Just x
Nothing special about conditionals
if True yes no = yes
if False yes no = no
Working with data
Easy to define common idioms
for processing data
Eg. 'mapping' same operation over a list
Or filtering values which pass a test
Higher order functions
... doing things with functions
map (\x -> x + 2) [1,2,3]
map is like a for-loop
Composing two functions
A fundamental operation
New functions from old
Programming with pipelines
foo = unwords
. map reverse
. words
"abc def ghi" to
"cba fed ihg"
Code is data
Haskell (almost) lets us treat
functions like any other kind of data
* very flexible
* very articulate
Notice the difference
Transformations on data,
rather than detailed list of steps
Declarative programming
Advanced type system
Few type annotations
Powerful type inference
No runtime checks at all
A useful safety net
Good balance!
Overloading
"Type classes" = name overloading
Superset of Java interfaces
Eg "show" on Ints and Strings
and [Int] and [[Int]] and [[[Int]]] and ...
The Real World
IO, State, Concurrency ...
Doesn't seem to fit nicely
The Real World has a type
type IO a = World -> (a, World)
Side effects change the world etc
If we compose these in right order,
things happen in the right order
Monads are not scary
Just a generalised wrapper
around things like World -> (a, World)
Allows imperative style
where needed
Does what it says...
main = do
putStr "Type something"
l <- getLine
appendFile "f" $ "IN:" ++ show l
High-level programming with actions
mapM' [Monday .. Friday] $ \d -> do
putStr $ "Day is: " ++ show d
putStr $ show $ some_calc d
let acts = map putStr $ words "hi all"
sequence acts
Easy to define new control structures
Trivial to implement callbacks too
A thought
How much of a program
needs state or IO?
Probably not much!
Many benefits
of clean separation
"Sin bin"...
Domain specific languages
Haskell's flexibility and syntax
strongly support embedded DSLs
This is a directly runnable parser
s = memo S $ iI np vp Ii
np = memo NP $ term "n"
<+> iI (term "d") (term "n") Ii
<+> iI np pp Ii
pp = memo PP $ iI (term "p") np Ii
vp = memo VP $ iI (term "v") np Ii
<+> iI vp pp Ii
student_info = do
let cs = [ tr << map (td<<) [n, s_name n, t]
| pn <- [1 .. maximum $ map fst projs]
, S n d c <- sort all_people
, current c == pn
, let (P s _ _ t) = get_proj pn ]
let header = tr << (map (th<<) ["uid", "name", "title"])
let doc = [ h1 << "Project allocation (2007-08)"
, h2 << "Student names vs project titles"
, table ! [border 1] << (header : cs)
, h3 << anchor ! [href "..."] << "some page" ]
writeFile "foo.html" $ show doc
... a database table join
formatting results in Html
echoes of LINQ?
Design principles
Think about the data and its operations
Use flexibility to create useful abstractions
Often good to invent DSLs to help
Typical: simple pieces with strong 'glue'
Testing etc
Hoare: No obvious defects,
vs obviously no defects
Code tends to be simpler,
and less chance for error
Some good testing tools exist
Performance issues
'Lazy' = slow?
Loss of 'control'?
Trust
your
compiler!
GHC is very advanced:
lots of fusion and inlining
Much better at it than you are
Good Analysis tools and
low-level options exist
A playground
Many experimental extensions
Lots of research activity
Strong community too
Still not there yet
Find the type error in the
following Haskell expression:
if null xs then tail xs else xs
Dependent types anyone?
Conclusion
Not much missing now
Quite a few advantages
Any one for a HUG?