280 likes | 513 Views
Haskell and HaskellVV. What is Haskell?. “Haskell is a polymorphically typed, lazy, pure functional language.” www.haskell.org So what does this mean?. Imperative (C, C++) Program is a sequence of steps Subroutines are called in a specific order How to calculate. Functional (Lisp, ML)
E N D
What is Haskell? • “Haskell is a polymorphically typed, lazy, pure functional language.” • www.haskell.org • So what does this mean?
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 Haskell is…a functional language
…a pure functional language • No side effects!
num = 2 inc x = 1 + x add x y = x + y num :: Int inc :: Int → Int add :: Int → Int → Int Types in Haskell • Could be Int → Int → Int • or • could be Int → (Int → Int) • a function returning a function!
Types in Haskell • (add 1) :: Int → Int • (add 1) x = 1 + x • inc = add 1 “currying”
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) xs gt = 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… • Side-effects are precisely controlled • 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 lbl replaceWithOp q p lbl return 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 be someOperation = synchronize ( map handleOne (getNeighbours mesh)) where handleOne (p,q) = do lbl ← delayInsertVertex p q someOtherOperation 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.