我正在为一个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.
我哪里错了?
谢谢!
[[更新]]
我已按照以下答案中的建议更改了代码。这是带错误的代码的链接。如果有人看看它并告诉我哪里出错了会很棒。
再次感谢!
答案 0 :(得分:8)
你不能这样写:
fmap f (Node [Tree a]) = ...
因为Tree
是数据类型而不是数据构造函数。在模式匹配中,您只能使用数据构造函数,在这种情况下,Leaf
或Node
。在这里,您甚至不需要匹配子树的每个构造函数,因为您无论如何都要直接传递整个列表:
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
实例进行组合。