Post on 19-Dec-2015
What is Haskell?
• “Haskell is a polymorphically typed, lazy, pure functional language.”
– www.haskell.org
• So what does this mean?
Haskell is…a functional language
Imperative (C, C++)• Program is a
sequence of steps• Subroutines are
called in a specific order
• How to calculate
Functional (Lisp, ML)• Program is a single
function evaluation• Sub-expressions are
evaluated when needed
• What is calculated
Types in Haskell
• num = 2
• inc x = 1 + x
• add x y = x + y
num :: Int
inc :: Int → Int
add :: Int → Int → Int
• Could be Int → Int → Int or• could be Int → (Int → Int)
• a function returning a function!
Other types
• Bool, Char
• [] are lists– [Bool] or [Char] (String = [Char])
• (,) (,,) and so on are pairs, triples, n-tuples– (Bool , Int) or (Bool , [Char] , Int)
• [(Bool , [Char → Int] , [[(Char,Bool)]])]
…is a functional language (2)
• Functions are first-order objects!
• Functions can be passed as arguments:– sort :: [Int] → [Int]– sortBy :: (Int → Int → Bool) → [Int] → [Int]
– sortBy (<)– sortBy (>)– sortBy (customOrdering)
…is polymorphically typed
• sortBy :: (a → a → Bool) → [a] → [a]
• a can be any type:– sortBy :: (Int → Int → Bool) → [Int] → [Int]– sortBy :: (Char→Char→Bool) → String →String– sortBy :: ((Int , Int) → (Int , Int) → Bool) →
[(Int , Int)] → [(Int , Int)]
• sortBy (<) :: [a] → [a] (more or less)
Example: quicksort
qsort :: [a] → [a]qsort [] = []qsort (x:xs)= (qsort lt) ++ [x] ++ (qsort gt)
where lt = filter (<x) xsgt = filter (>x) xs
We could also write qsortBy, replacing (<x) with (f x)
Haskell is lazy
• eg. head (qsort list)– Only the first element is needed, so the lists gt
are never computed!
• qsort (x:xs) = (qsort lt) ++ …• = (qsort (l:ls) ++ …) ++ …
…• = ((…(qsort [] ++ [y] ++ …)…• qsort (x:xs) = y
One more important function
• map :: (a → b) → [a] → [b]
• Applies a function f to every element in a list (or, more generally, any data structure)
• eg. map (*2) [1,2,3] = [2,4,6]
HaskellVV
• mesh, vtxLabel, vtxData ← polymorphic• No global state → labels particular to mesh• Query functions like
– prevTo :: mesh → vtxLabel → vtxLabel → vtxLabel– lookupData :: mesh → vtxLabel → vtxData
• Update functions like– setNB :: mesh → vtxLabel → [vtxLabel] → mesh– lookupData :: mesh →
(vtxLabel → vtxData → vtxData) → mesh
HaskellVV
• Long operations are clumsy
insertVertex m p q x
= replaceWith (
replaceWith (
setNB m x [p,q] )
p q x)
q p x)
HaskellVV
• There are ways around this:
insertVertex m p q x
= let m1 = setNB m x [p,q] in
let m2 = replaceWith m1 p q x in
let m3 = replaceWith m2 q p x in
…
• The problem remains: we want sequential operations.
Monads
• Mathematical structures offering operations which satisfy certain rules
…
• Imperative operations are monads!
Monads
• provide a way to incorporate ‘side effects’
• eg. I/O operations– putStr :: String → IO ()– getStr :: IO String
• (getStr >>= \str → putStr str) :: IO ()
• (do { str ← getStr; putStr str; }) :: IO ()
Monads
• This looks like imperative code, but…
1. Side-effects are precisely controlled
2. These are first-order objects!– map putStr [“one” , ”two” , ”three” , …]
• is actually a list of I/O operations
– [IO ()] , ([IO String] , Bool → IO ())– sequence [do {str ← getStr; putStr str; } ,
(putStr “foo”) , …]
Monads and HaskellVV
• use a monad MeshOp:prevToOp :: vtxLabel→vtxLabel→MeshOp vtxLabel
setNBOp :: vtxLabel → [vtxLabel] → MeshOp ()
• MeshOp is just an operation:• executeMeshOp :: MeshOp () → mesh → mesh
Example: insertVertex
insertVertex :: vtxLabel → vtxLabel →MeshOp vtxLabel
insertVertex p q = do lbl ← newVertexOp
setNBOp lbl [p,q]replaceWithOp p q lblreplaceWithOp q p lblreturn lbl
Monads and HaskellVV
• Some things are easy (like forall):map someOperation (listVertices mesh)
map insertVertex (listNeighbours mesh)
• However, many vv programs require two (or more) passes through a forall statement
• Hmmm…maybe Haskell can help here?
Delay monads
• The Delay monad lets you arbitrarily delay an operation:synchronize ( do { delay a; b; }) ↔ do { b; a; }
• A vertex or pair can be dealt with in one go:synchronize (map doSomething (getVertices mesh))
Example: delayedInsertVertex
dInsertVertex :: vtxLabel →vtxLabel →MeshOp vtxLabel
dInsertVertex p q = do lbl ← newVertexOp
delay (do setNBOp lbl [p,q]
replaceWithOp p q lbl replaceWithOp q p
lbl)return lbl
Example, continued
• An operation can then besomeOperation = synchronize ( map handleOne
(getNeighbours mesh))
where handleOne (p,q)= do lbl ← delayInsertVertex
p qsomeOtherOperation p q
• someOtherOperation uses all of the old neighbourhoods!
Conclusion
• What’s good about Haskell (and HaskellVV?)– Delayed operations– Strict semantics (no side-effects)– Easier to understand the code– Operations are implementation independent
– Haskell code can be as fast as C / C++– Windowing support, OpenGL libraries, …
Conclusion
• What’s bad about Haskell (and HaskellVV?)– Haskell is functional and lazy
• Expressions are stored until evaluated (or garbage collected)
• If you’re not careful, the heap can fill up with unevaluated expressions
– Current implementation of vv is slow
What have I left out?
• Type classes– define what functions may be applied to a
type– for instance, (<) :: a → a → Bool is only
defined for a in class Ord:• (<) :: (Ord a) => a → a → Bool
– HaskellVV defines classes• Mesh mesh vtxLabel vtxData• MeshOp op mesh vtxLabel vtxData• VectorSpace field vector• and others
More information
• http://www.haskell.org– Haskell homepage, lots of information, plus
compilers, interpreters, etc.
• http://www.cpsc.ucalgary.ca/~laneb/HaskellVV– Adding my code, will archive this presentation, etc.