【问题标题】:Tree as instance of functor and foldable树作为函子和可折叠的实例
【发布时间】:2013-11-14 22:27:36
【问题描述】:

我正在为一个硬件问题编写一个小代码,它要求我们将树的定义定义为函子和可折叠的实例。当我写下面的代码时:

 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

再次感谢!

【问题讨论】:

    标签: haskell data-structures functional-programming functor


    【解决方案1】:

    你不能这样写:

    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 视为修改结构内部 的值,但根本不改变结构的形状。 IE。映射到一个列表会产生一个长度相同的列表,映射到一棵树应该会产生一棵相同的树,具有所有相同的分支,但叶节点中的值不同。

    您可以将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 实例组合。

    【讨论】:

    • 技术上Tree 是一种构造函数:类型构造函数。所以它生成类型 vs Node 生成值
    • @jozefg 有点挑剔!但是好的,我改变了它:)
    • @PeterHall 非常感谢!我已根据您的建议对您的代码进行了更改,但仍会引发错误消息您可以在此处查看带有错误消息的更新代码:snipt.org/Bahjg5
    • @user2994154 当您为(Tree a) 定义fmap 时,fmap 的第一个参数是一个接受(a -> b) 的函数。在您的定义Node (fmap f t) 中,您期望fmapTree a -> Treee b。为什么不 Node (fmap (fmap f) t) 相当于 Node [fmap f a | a <- t]
    • @homam 我刚刚想通了,但感谢您的反馈。可折叠实例会以类似的方式工作吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    • 1970-01-01
    • 2019-03-02
    相关资源
    最近更新 更多