Search code examples
haskelltrie

Implementing Foldable for a Trie


I want to make my Trie data structure foldable. The basic data structure looks like this:

data Trie a = Trie {
    value :: Maybe a,
    children :: [(Char, Trie a)]
} deriving (Show)

I tried to implement the Foldable class by defining foldr:

instance F.Foldable Trie where
    foldr f z (Trie (Just v) children) =
        F.foldr (\a b -> F.foldr f b a) (f v z) children

    foldr f z (Trie Nothing children) =
        F.foldr (\a b -> F.foldr f b a) z children

This does not compile with this error:

Couldn't match type `a' with `Trie a'
  `a' is a rigid type variable bound by
      the type signature for foldr :: (a -> b -> b) -> b -> Trie a -> b
      at Trie.hs:17:5
Expected type: [(Char, a)]
  Actual type: [(Char, Trie a)]
In the third argument of `F.foldr', namely `children'
In the expression:
  F.foldr (\ a b -> F.foldr f b a) (f v z) children

However, if I change the type of children to Map Char (Trie a), the Foldable implementation works without a change. I would like to keep the association list for simplicity's sake at the moment. Could you explain to me why foldr behaves differently on a map and an association list?


Solution

  • The error is because you are attempting to fold over a list of key-value pairs, rather than a list of Tries. What you want to do is ignore the Char keys and just fold into each of the child nodes as so

    foldr f z (Trie (Just v) children) =
        F.foldr (\(_, a) b -> F.foldr f b a) (f v z) children
    
    foldr f z (Trie Nothing children) =
        F.foldr (\(_, a) b -> F.foldr f b a) z children