Transcript

Haskell and HaskellVV

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

…a pure functional language

• No side effects!

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!

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) 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.


Recommended