9

For example, I have some data type. Let it be a binary tree:

data Tree a = Leaf a | Branch (Tree a) (Tree a)

For example, I implemented traversal of the tree:

treeFoldt :: Tree t -> [t]
treeFoldt = foldt1 (:) []

It works pretty good. But I want to implement Foldable interface.

I think, that I should write something like that:

instance Foldable Tree where
  foldr = treeFoldt

But it does not work. How can I fix this?

David
  • 674
  • 6
  • 19

1 Answers1

14

I could try to tell you where the problem with your code is but sadly you did not give the definition for foldt1

But this should work (if your implementation of treeFoldt is ok - remember: [] is an instance of Foldable):

instance Foldable Tree where
  foldr f s = Data.Foldable.foldr f s . treeFoldt

basic definition using Monoid

Anyway, I think the easiest way in this case is to implement just the foldMap part:

import Data.Foldable
import Data.Monoid

data Tree a = Leaf a | Branch (Tree a) (Tree a)

instance Foldable Tree where
 foldMap f (Leaf a)     = f a
 foldMap f (Branch l r) = foldMap f l `mappend` foldMap f r 

and this surely works.

Examples / Usage

λ> let t = Branch (Branch (Leaf $ Sum 2) (Leaf $ Sum 4)) (Leaf $ Sum 6)
λ> fold t
Sum {getSum = 12}

or

λ> let t = Branch (Branch (Leaf 2) (Leaf 4)) (Leaf 6)
λ> foldMap Sum t
Sum {getSum = 12}

and of course you don't need the Monoid part at all - the default implementations work just fine:

λ> Data.Foldable.foldr1 (+) t
12

by the way: it's most likely not obvious how foldr1 (+) can be expressed just in terms of foldMap and it's a nice (advanced) exercise to try to do it on your own :D


external resources

I think Foldable and Traversable by A. Arnold is quite a nice blog post on Foldable (and Traversable) in general - maybe you find it helpful too

Community
  • 1
  • 1
Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • tree data structure is just example. Real question is, what I have to do, if I have `foldr function` implementation and I want to implement `Foldable interface`. – David Mar 27 '15 at 08:12
  • 1
    if you already have something giving you back a list than you can see the remark I made - if not you have to think about your structure - IMO the easiest way is to use `mappend` and `fmap` as it's just a matter of thinking about how to *flatten* out the structure and connecting it with `mappend`s – Random Dev Mar 27 '15 at 08:17
  • 2
    Although @David doesn't give the definition of `foldt1`, the way he is *using* it makes me suspect he could use `foldr = foldt1`. That this is equivalent to your first version is basically the `build/foldr` fusion rule for lists, if only `foldt1` is polymorphic enough. (Although since he doesn't use `GHC.Exts.build` explicitly, GHC probably won't be able to detect this.) – Ørjan Johansen Mar 27 '15 at 10:26