
Hi, I'm playing around with Functors in Haskell with the aim of understanding more structured functors, particularly applicative functors and traversable and foldable. I'm using the standard binary tree type to play around with this, as follows: data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a) I think I understand Functor fine: instance Functor Tree where fmap f Empty = Empty fmap f (Leaf x) = Leaf (f x) fmap f (Node l x r) = Branch (fmap f l) (f x) (fmap f r) (with (<$>) being a synonym for fmap). This satisfies the laws for Functor (I'll omit details). Likewise, I think I'm fine with Foldable, for Tree a over any monoid a: instance Foldable Tree foldMap f Empty = mempty foldMap f (Leaf x) = f x foldMap f (Node l x r) = foldMap f l `mappend` f x `mappend` foldMap f r Where I'm stuck is with Applicative: class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b I understand that pure lifts a value into the applicative functor, so this one is easy: pure = Leaf but I cannot see what <*> should look like. I know that <*> is essentially application ($) lifted into the functor, so if the functor were also a monad then <*> would be liftM2 ($), I suppose. But I want a "direct" implementation, without monads floating about, but I cannot see what to do. I think then I would be able to define an instance for traversable as something like this: instance Traversable Tree traverse f Empty = pure Empty traverse f (Leaf x) = Leaf `fmap` f x traverse f (Node l x r) = Node `fmap` traverse f (l <*> f x <*> traverse f r) (I think that <*> must be associative). Can anyone advise what <*> should look like, please? Thanks in advance for your help. Darryn.

On Mon, 2010-03-22 at 11:59 +1030, Darryn Reid wrote:
Where I'm stuck is with Applicative: class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
I understand that pure lifts a value into the applicative functor, so this one is easy: pure = Leaf but I cannot see what <*> should look like. I know that <*> is essentially application ($) lifted into the functor, so if the functor were also a monad then <*> would be liftM2 ($), I suppose. But I want a "direct" implementation, without monads floating about, but I cannot see what to do.
Hmm. When I played with trees I've done: data Tree a = Leaf | Node (Tree a) a (Tree a) instance Applicative Tree where pure x = let t = Node t x t in t -- if you prefer Node (pure x) x (pure x) -- or fix (\t -> Node t x t) Leaf <*> _ = Leaf _ <*> Leaf = Leaf (Node l f r) <*> (Node l' v r') = Node (l <*> l') (f v) (r <*> r') So maybe: instance Applicative Tree where pure x = let t = Node t x t in t -- if you prefer Node (pure x) x (pure x) Empty <*> _ = Empty _ <*> Empty = Empty (Leaf f) <*> (Leaf v) = Leaf (f v) (Leaf f) <*> (Node _ v _) = Leaf (f v) (Node _ f _) <*> (Leaf v) = Lead (f v) (Node l f r) <*> (Node l' v r') = Node (l <*> l') (f v) (r <*> r') Both have unpleasant property of function returning infinite tree. Regards PS. Why do you need Leaf? How does Leaf x differ from (Node Empty x Empty)?

On Mon, Mar 22, 2010 at 11:59:56AM +1030, Darryn Reid wrote:
Hi,
Where I'm stuck is with Applicative: class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
I think there are actually lots of different Applicative instances for Tree, just like there are (at least) two Applicative instances for lists, one that "zips" the lists elementwise and one that takes all possible combinations. You can do something similar with trees; Maciej's instance corresponds to "zipping" two trees together, but you can also do something like combining the functions in the first tree in every possible way with the values in the second tree, the complicated part is figuring out how to put all these results back together into a tree. But at any rate, you *don't* need an Applicative instance in order to define a Traversable instance. Traversable instances follow a nice regular pattern; they look exactly like Functor instances but with normal application replaced by application in an Applicative context. So, in your case: instance Traversable Tree where traverse f Empty = pure Empty traverse f (Leaf x) = Leaf <$> f x traverse f (Node l x r) = Node <$> traverse f l <*> f x <*> traverse f r The thing to keep in mind is that the Applicative instance being used here is NOT the one for Tree (which need not even have one), it is whatever Applicative the caller of traverse is choosing to use as the context of the traversal. All the traverse implementation has to do is apply f to every value in the tree from left to right. -Brent
participants (3)
-
Brent Yorgey
-
Darryn Reid
-
Maciej Piechotka