开发者

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜