树作为仿函数和可折叠的实例

时间:2013-11-14 22:27:37

标签: haskell data-structures functional-programming functor

我正在为一个hw问题编写一些代码,它要求我们将树的定义作为functor和foldable的一个实例。当我写下面的代码时:

 import Data.Foldable
 import Data.Monoid

 data Tree a = Leaf a
              | Node [Tree a] 
     deriving (Show) 

 instance Functor (Tree) where
    fmap f (Leaf a) = Leaf (f a) 
    fmap f (Node [Tree a]) = fmap f [Tree a]

 instance Foldable (Tree) where
    foldMap f (Leaf a) = f a
    foldMap f (Node [Tree a]) = foldMap f `mappend` [Tree a]

出现以下错误:

hw.hs:10:19:
Not in scope: data constructor `Tree'
Perhaps you meant `True' (imported from Prelude)

hw.hs:10:38:
Not in scope: data constructor `Tree'
Perhaps you meant `True' (imported from Prelude)

hw.hs:14:22:
Not in scope: data constructor `Tree'
Perhaps you meant `True' (imported from Prelude)

hw.hs:14:54:
Not in scope: data constructor `Tree'
Perhaps you meant `True' (imported from Prelude)
Failed, modules loaded: none.

我哪里错了?

谢谢!

[[更新]]

我已按照以下答案中的建议更改了代码。这是带错误的代码的链接。如果有人看看它并告诉我哪里出错了会很棒。

http://snipt.org/Bahjg5

再次感谢!

1 个答案:

答案 0 :(得分:8)

你不能这样写:

fmap f (Node [Tree a]) = ...

因为Tree是数据类型而不是数据构造函数。在模式匹配中,您只能使用数据构造函数,在这种情况下,LeafNode。在这里,您甚至不需要匹配子树的每个构造函数,因为您无论如何都要直接传递整个列表:

fmap f (Node t) = fmap f t

但实际上还有另一个错误。 fmap的结果仍然需要Tree,因此您需要将结果放回Node

fmap f (Node t) = Node (fmap f t)

就像你已经在处理Leaf案例一样。


您可以将fmap视为修改 结构中的值的内容,但根本不更改结构的形状。即。映射列表将生成相同长度的列表,并且树上的映射应该生成相同的树,具有所有相同的分支,但在叶节点中具有不同的值。

您可以将fold视为完全删除结构的内容,然后找到将叶节点中的所有值组合为单个值的方法。 foldMap的类型有助于:

 foldMap :: (Foldable t, Monoid m) => 
         (a -> m) -- mapping function from `a` to the monoid result
      -> t a      -- A tree node containing values of type `a`
      -> m        -- a monoid

foldMap的结果不应该是Tree!它只是值,使用映射函数进行转换,并使用Monoid实例进行组合。