Generalized foldr and foldl for using with generic Haskell trees?
How can I write general开发者_如何学Cized foldr and foldl function for generic Haskell trees, given this definition?
data (Eq a, Show a) => Tree a = Void | Node a [Tree a]
deriving (Eq, Show)
treefoldr :: (Eq a, Show a) =>
(a -> b -> c) -> c -> (c -> b -> b) -> b -> Tree a -> c
treefoldl :: (Eq a, Show a) =>
(b -> a -> c) -> c -> (c -> b -> b) -> b -> Tree a -> c
Even if I can understand how foldr and foldl functions work in Haskell, I'm not quite sure how to write this generalized function for trees.
EDIT: I tried something like this (not even compiling):
treefoldr _ g1 _ _ Void = g1
treefoldr f1 g1 f2 g2 (Node a ts) = f1 a (foldr f2 g2 ts)
EDIT 2: another try...
treefoldr _ z1 _ _ Void = z1
treefoldr f z1 g z2 (Node a ts) =
f a (foldr g z2 (map (\x -> treefoldr f z1 g z2 x) ts))
treefoldl _ z1 _ _ Void = z1
treefoldl f z1 g z2 (Node a ts) =
f (foldl g z2 (map (\x -> treefoldl f z1 g z2 x) ts)) a
treefoldr
is working, however treefoldl
not:
Couldn't match expected type `c' against inferred type `b' `c' is a rigid type variable bound by the type signature for `treefoldl' at trees.hs:47:42 `b' is a rigid type variable bound by the type signature for `treefoldl' at trees.hs:47:32 In the first argument of `foldl', namely `g' In the first argument of `f', namely `(foldl g z2 (map (\ x -> treefoldl f z1 g z2 x) ts))' In the expression: f (foldl g z2 (map (\ x -> treefoldl f z1 g z2 x) ts)) a
The error message in full:
Couldn't match expected type `c' against inferred type `Tree a'
`c' is a rigid type variable bound by
the type signature for `treefoldr' at so.hs:5:14
Expected type: [c]
Inferred type: [Tree a]
In the third argument of `foldr', namely `ts'
In the second argument of `f1', namely `(foldr f2 g2 ts)'
That means that
ts
is of type[Tree a]
- you are using it as the third argument to
foldr
foldr
expects its third argument to be of type[c]
[c]
and[Tree a]
are different types, hence this is an error
So you need to process ts
into something of type [c]
and pass that result to foldr
instead of ts
itself. The map function would be a good place to start.
I don't know if such a solution is allowed for your homework, but when the use of type classes is okay, you could write
import Data.Foldable
import Data.Monoid
data Tree a = Void | Node a [Tree a]
deriving (Eq, Show)
instance Foldable Tree where
foldMap f Void = mempty
foldMap f (Node value []) = f value
foldMap f (Node value (x:xs)) = foldMap f x `mappend` foldMap f (Node value xs)
Using this definition the implementation of your functions should be trivial, as Foldable defines a foldl, foldr etc.
I have talk to the same your professor, at the end I found the right solution:
treefoldr :: (Eq a, Show a) => (a -> b -> c) -> c -> (c -> b -> b) -> b -> Tree a -> c
treefoldr _ z1 _ _ Void = z1
treefoldr f z1 g z2 (Node a ts) = f a $ foldr (aggr) z2 ts
where
aggr t z = g (treefoldr f z1 g z2 t) z
treefoldl :: (Eq a, Show a) => (b -> a -> c) -> c -> (c -> b -> b) -> b -> Tree a -> c
treefoldl _ z1 _ _ Void = z1
treefoldl f z1 g z2 (Node a ts) = f (foldl (aggr) z2 ts) a
where
aggr z t = g (treefoldl f z1 g z2 t) z
Regards
精彩评论