Lecture 14. Foldables and traversables Functional Programming 2019/20 Matthijs Vákár [ Faculty of Science Information and Computing Sciences] 0
Goals ▶ How do we calculate summaries of data structures other than lists? ▶ Learn about Monoid and Foldable type classes ▶ How do we map impure functions over data structures? ▶ Learn about Applicative and Traversable type classes ▶ See some examples of monadic and applicative code in action. Chapter 14 from Hutton’s book [ Faculty of Science Information and Computing Sciences] 1
data Tree a = Leaf | Node (Tree a) a (Tree a) data Rose a = RLeaf | RNode a [Rose a] data Expr x = Var x | Val Int | Add (Expr x) (Expr x) Our three example data types for today Binary trees: Rose trees: ASTs: [ Faculty of Science Information and Computing Sciences] 2
Linear summaries: Monoids and Foldables [ Faculty of Science Information and Computing Sciences] 3
Summaries to calculate ▶ Sums, products of entries ▶ And/or of entries ▶ Used variables ▶ Composition of all functions in data structure ▶ Parity of Booleans in data structure Monoids and folds abstract the idea of combining elements in a well-behaved way! [ Faculty of Science Information and Computing Sciences] 4
class Monoid m where mempty mappend :: m -> m -> m mconcat :: [m] -> m mconcat = foldr mappend mempty Monoids Some types have an intrinsic notion of combination ▶ We already hinted at it when describing folds ▶ Monoids provide an associative binary operation with an identity element :: m [ Faculty of Science Information and Computing Sciences] 5
mempty instance Monoid [t] where = [] -- empty list mappend = (++) -- concatenation mconcat = concat Monoids: example Lists [T] are monoids regardless of their contained type T The simplest monoids in a sense (jargon: free monoids) [ Faculty of Science Information and Computing Sciences] 6
mempty <> y = y -- left identity x <> mempty = x -- right identity (x <> y) <> z = x <> (y <> z) -- associativity Monoid laws Monoids capture well-behaved notion of combination, respecting these laws: We write mappend infjx as <> . Do these remind of you anything? [ Faculty of Science Information and Computing Sciences] 7
Some examples of monoids Can you come up with some examples of monoids? [ Faculty of Science Information and Computing Sciences] 8
Note that monoids may be non-commmutative, so that foldl :: (b -> a -> b) -> b -> [a] -> b foldr :: (a -> b -> b) -> b -> [a] -> b foldr mappend mempty = foldl mappend mempty foldr mappend mempty /= foldr (flip mappend) mempty Folds and Monoids Recall, folding on lists: We have seen, because of associativity and identity laws: for any monoid! [ Faculty of Science Information and Computing Sciences] 9
foldl :: (b -> a -> b) -> b -> [a] -> b foldr :: (a -> b -> b) -> b -> [a] -> b foldr mappend mempty = foldl mappend mempty foldr mappend mempty /= foldr (flip mappend) mempty Folds and Monoids Recall, folding on lists: We have seen, because of associativity and identity laws: for any monoid! Note that monoids may be non-commmutative, so that [ Faculty of Science Information and Computing Sciences] 9
foldr :: (a -> b -> b) -> b -> [a] -> b foldMap :: Monoid m => (a -> m) -> [a] -> m Generalizing foldr? (a -> b -> b) -> [a] -> b -> b (a -> End b ) -> [a] -> End b Does this buy us anything? [ Faculty of Science Information and Computing Sciences] 10
foldr :: (a -> b -> b) -> b -> t a -> b foldMap :: Monoid m => (a -> m) -> t a -> m Foldables Want: or for some other container type t . t had better be a functor… [ Faculty of Science Information and Computing Sciences] 11
class Functor t => Foldable t where foldr op i = ??? foldMap :: Monoid m => (a -> m) -> t a -> m foldMap f = ??? toList :: t a -> [a] fold :: Monoid m => t m -> m fold = ??? Foldables Data structure we can fold over, like lists: foldr :: (a -> b -> b) -> b -> t a -> b toList = ??? [ Faculty of Science Information and Computing Sciences] 12
class Functor t => Foldable t where foldr op i = foldr op i . toList foldMap :: Monoid m => (a -> m) -> t a -> m foldMap f = mconcat . map f . toList toList :: t a -> [a] fold :: Monoid m => t m -> m fold = foldMap id Foldables Data structure we can fold over, like lists: foldr :: (a -> b -> b) -> b -> t a -> b toList = foldr (:) [] In essence, a data type that we can linearize to a list… [ Faculty of Science Information and Computing Sciences] 13
Some examples Let’s implement Foldable for Tree , Rose and Expr ! See how they solve our initial problem! [ Faculty of Science Information and Computing Sciences] 14
Mapping Impure Functions: Applicatives and Traversables [ Faculty of Science Information and Computing Sciences] 15
Mapping impure functions ▶ A stateful walk of a tree ▶ A walking a rose tree while performing IO ▶ Trying to evaluate an expression while accumulating errors ▶ Idea: keep shape of data structure; replace entries using impure function; accumulate side efgects on the outside Applicatives and traversals abstract the idea of mapping impure functions in a well-behaved way! [ Faculty of Science Information and Computing Sciences] 16
class Functor f => Applicative f where class Functor f where pure (<*>) :: f (a -> b) -> f a -> f b class Applicative f => Monad f where return :: a -> f a -- equals Applicative's pure (>>=) :: f a -> (a -> f b) -> f b The functor - applicative - monad hierarchy fmap :: (a -> b) -> f a -> f b :: a -> f a [ Faculty of Science Information and Computing Sciences] 17
af <*> ax = do f <- af pure = return return (f x) Recall: Applicatives from Monads Every monad induces an applicative x <- ax But not every applicative arises that way! [ Faculty of Science Information and Computing Sciences] 18
Why not from a monad? (Error m1) <*> (Error m2) = Error (m1 <> m2) = OK (f a) <*> (OK a) (OK f) <*> (Error m2) = Error m2 (OK f) = Error m1 (Error m1) <*> (OK a) = OK pure instance Monoid m => Applicative (Error m) where data Error m a = Error m | OK a Example: Error Accumulation Example of Applicative that does not come from Monad How is Error m a functor? An applicative? [ Faculty of Science Information and Computing Sciences] 19
= OK (OK f) = OK (f a) data Error m a = Error m | OK a instance Monoid m => Applicative (Error m) where pure <*> (OK a) (Error m1) <*> (Error m2) = Error (m1 <> m2) (Error m1) <*> (OK a) = Error m1 (OK f) <*> (Error m2) = Error m2 Example: Error Accumulation Example of Applicative that does not come from Monad How is Error m a functor? An applicative? Why not from a monad? [ Faculty of Science Information and Computing Sciences] 19
class Foldable t => Traversable t where (a -> f b) -> t a -> f (t b) traverse g ta = ??? sequenceA :: Applicative f => t (f a) -> f (t a) sequenceA = ??? Traversables Data structure we can traverse/walk: traverse :: Applicative f => Think of traverse as a map over t using an impure function :: a -> f b [ Faculty of Science Information and Computing Sciences] 20
class Foldable t => Traversable t where (a -> f b) -> t a -> f (t b) traverse g ta = sequenceA (fmap g ta) sequenceA :: Applicative f => t (f a) -> f (t a) sequenceA = traverse id Traversables Data structure we can traverse/walk: traverse :: Applicative f => Think of traverse as a map over t using an impure function :: a -> f b [ Faculty of Science Information and Computing Sciences] 21
Some examples Let’s implement Foldable for Tree , Rose and Expr ! [ Faculty of Science Information and Computing Sciences] 22
Traversals are impure maps: instance Monad Identity' where newtype Identity' a = Identity' {runIdentity' :: a} return x = Identity' x = f (runIdentity' x) fmap :: Traversable t => (a -> b) -> t a -> t b fmap == runIdentity . traverse (Identity . f) Traversing with the Identity Applicative We have the identity monad x >>= f [ Faculty of Science Information and Computing Sciences] 23
instance Monad Identity' where newtype Identity' a = Identity' {runIdentity' :: a} return x = Identity' x = f (runIdentity' x) fmap :: Traversable t => (a -> b) -> t a -> t b fmap == runIdentity . traverse (Identity . f) Traversing with the Identity Applicative We have the identity monad x >>= f Traversals are impure maps: [ Faculty of Science Information and Computing Sciences] 23
Relating Monoids and Applicatives, Folds and Traversals [ Faculty of Science Information and Computing Sciences] 24
Claim: traversing with Const is the same as folding: instance Monoid m => Applicative (Const m) where newtype Const a b = Const { getConst :: a } pure _ = Const mempty (<*>) (Const f) (Const b) = Const (f <> b) foldMap :: (Traversable t, Monoid m) => (a -> m) -> t a -> m foldMap f = getConst . sequenceA . fmap (Const . f) Phantom Types: All Monoids Are Applicatives Introduce fake type dependency: [ Faculty of Science Information and Computing Sciences] 25
Recommend
More recommend