# Real World Haskell: Lecture 5

Post on 12-May-2015

1.536 views

Embed Size (px)

TRANSCRIPT

<ul><li>1.Real World Haskell:Lecture 5 Bryan OSullivan2009-11-04 </li></ul>
<p>2. Adding quaternionsWe add two quaternions by adding their coecients.a+ bi +cj + dk+ w+ xi +yj + zk=(a + w ) + (b + x)i + (c + y )j + (d + z)k Or, in Haskell: addQ (Q a b c d ) (Q w x y z ) =Q ( a+w) ( b+x ) ( c+y ) ( d+z ) 3. Subtracting quaternionsSubtraction is dened similarly.subQ (Q a b c d ) (Q w x y z ) =Q ( aw) ( bx ) ( cy ) ( dz ) 4. Typeclass inheritanceThe Eq typeclass that we met last week lets us compare values forequality.For many values, we want to be able to compare them for (total)ordering, for which we use the Ord typeclass. c l a s s ( Eq a ) = Ord a where>compare : : a > a > Ordering Notice the constraint on the Ord class: this states that in order fora type to be an instance of Ord, it must already be an instance ofEq. 5. The Num typeclassHaskell denes a typeclass named Num that lets us express common arithmetic operations:c l a s s ( Eq a , Show a ) = Num a where >(+): : a > a > a(): : a > a > a(): : a > a > anegate : : a > aabs: : a > a{ e t c . } 6. Num and quaternions On rst glance, we can easily t our Quaternion type into the Num class.i n s t a n c e Num Q u a t e r n i o n where(+) = addQ() = subQ{ ??? } We quickly run into problems: its not obvious what negate or abs should do. Maybe we can do something with multiplication, though? 7. Multiplying quaternionsIf we can remember the identitiesi2 = j2 = k2 = ijk = 1 Then multiplication of quaternions falls out from the usual laws ofarithmetic, but takes a complicated form: a + bi + cj + dk w + xi + y j + zk = aw bx cy dz + (ax + bw + cz dy )i + (ay bz + cw + dx)j + (az + by cx + dw )k 8. Multiplying quaternions in Haskell Its easy to convert our equation into executable form:mulQ (Q a b c d ) (Q w x y z )= Q ( a w b x c y d z )( a x + bw + c z d y )( a y b z+ c w + d x )( a z + b y c x + dw) 9. Multiplying quaternions in Haskell Its easy to convert our equation into executable form:mulQ (Q a b c d ) (Q w x y z )= Q ( a w b x c y d z )( a x + bw + c z d y )( a y b z+ c w + d x )( a z + b y c x + dw) Does this mean that we should augment our denition of Num asfollows?i n s t a n c e Num Q u a t e r n i o n where( ) = mulQ{ e t c . } 10. Arithmetic laws There are some laws that are so ingrained into our minds that wenever think about them: m+n =n+m (commutative law of addition)(m + n) + k = m + (n + k)(associative law of addition) mn = nm (commutative law of multiplication)(mn)k = m(nk) (associative law of multiplication) 11. Laws for quaternionsWe can see by simple inspection that addition over quaternionsmust satisfy the commutative and associative laws of normalarithmetic.We used those familiar arithmetic laws to derive the formula forquaternion multiplication, but do quaternions satisfy thecommutative law of multiplication? Prelude> let a = Q 2 0 9 0Prelude> let b = Q 0 9 0 2 Prelude> a mulQ bQ 0.0 36.0 0.0 (-77.0) Prelude> b mulQ aQ 0.0 0.0 0.0 85.0 12. Laws: made to be broken?When you write or use a typeclass, theres an impliedunderstanding that youll obey its laws1 .Code that uses Eq relies on the fact that if a == b is True, thenb == a will be True too, and a /= b will be False.Similarly, code that uses Num implicitly relies on thecommutativity and associativity of addition and multiplication.1Unfortunately, these laws are often undocumented. 13. Laws: made to be broken?When you write or use a typeclass, theres an impliedunderstanding that youll obey its laws1 .Code that uses Eq relies on the fact that if a == b is True, thenb == a will be True too, and a /= b will be False.Similarly, code that uses Num implicitly relies on thecommutativity and associativity of addition and multiplication.Neither the type system nor any other aspect of Haskell will helpyou to do the heavy lifting here: The burden is on you, the creator of a type, to ensure that if you make it an instance of a typeclass, that it follows the laws. 1Unfortunately, these laws are often undocumented. 14. A sketchy approach Since quaternion multiplication is not commutative, we should notimplement (). But what more should we do?For instance, we could partially implement Num:i n s t a n c e Num Q u a t e r n i o n where(+) = addQ ( ) = undefinedWhat eect does this have on code that tries to use multiplication? Prelude> scalar 2 * scalar 3*** Exception: Prelude.undefined This is not very satisfactory behaviour. 15. Playing fast and loose Of course, Haskell itself doesnt escape the sin bin. What happensto those fancy laws in the presence of inexact arithmetic? Prelude> let a = 1e20 :: DoublePrelude> (a + (-a)) + 11.0Prelude> a + ((-a) + 1)0.0 (This is the same behaviour as every other language thatimplements oating point, by the way.)A conclusion? You can violate the rules, but the compiler cantremind you that youre cheating. 16. Code that might fail Youve probably seen this behaviour by now: Prelude> 1 div 0*** Exception: divide by zero These exceptions are often annoying, because we cant easily catchand handle them.There exists a predened type we can use to deal with these cases:data Maybe a = Nothing | Just aNotice that this type is parameterized, so we can have types suchas Maybe Int, or Maybe (String, Bool), or so on. 17. Safer functions via Maybe Safer integer division:a s a f e D i v 0 = Nothinga s a f e D i v b = Just ( a div b ) A safer version of head:safeHead [ ]= Nothings a f e H e a d ( x : ) = Just x 18. Exercise time!You should be familiar with the map function by now:map : : ( a > b ) > [ a ] > [ b ] Write the equivalent function for the Maybe type:mapMaybe : : ( a > b ) > Maybe a > Maybe b 19. Binary trees data Tree a = Empty| Node a ( Tree a ) ( Tree a )d e r i v i n g ( Eq , Ord , Show) l e a f v = Node v Empty Empty someOldTree =Node ( l e a f f o o ) ( Node ( l e a f b a r ) ( Node ( l e a f baz ) Empty ) ) 20. Sizing a trees i z e Empty = 0s i z e Node a b = 1 + s i z e a + s i z e b 21. Mapping again What should this function look like?mapTree : : ( a > b ) > Tree a > Tree b 22. Generalising mapping So far, weve seen three dierent container types, with threedierent map-like functions:map: : ( a > b ) > [ a ] > [ b ]mapMaybe : : ( a > b ) > Maybe a > Maybe bmapTree : : ( a > b ) > Tree a > Tree b It turns out we can write a typeclass to generalise this idea:c l a s s Functor f wherefmap : : ( a > b ) > f a > f b i n s t a n c e Functor Maybe wherefmap = mapMaybe 23. Homeworkbinary search treesTurn the Tree type into a binary search tree by dening thefollowing functions:i n s e r t : : ( Ord a ) = a > Tree a > Tree a >c o n t a i n s : : ( Ord a ) = a > Tree a > Bool > 24. Homeworkkey/value containersAdapt your binary search tree code for use to create a simple key/value container:type Map a b = Tree ( a , b )insertItem : : ( Ord a ) = a > b > Map a b > Map a b>lookupByKey : : ( Ord a ) = a > Map a b > Maybe b>listToMap : : ( Ord a ) = [ ( a , b ) ] > Map a b>mapToList : : Map a b > [ ( a , b ) ]minItem : : ( Ord a ) = Map a b > Maybe ( a , b )> </p>