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?
The error is because you are attempting to fold over a list of key-value
pairs, rather than a list of Trie
s. 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