编写TreeN的Functor实例时遭遇GHC类型不匹配错误的原因排查
解决TreeN Functor实例的类型不匹配问题
你的错误核心在于处理ParentN的子节点列表时,误用了TreeN.fmap去直接作用于列表——TreeN.fmap是专门用来映射TreeN类型的,而不是列表类型。
错误原因解析
看GHC给出的错误信息:
src/TreeN.hs:7:1: error: • Couldn't match type ‘TreeN t’ with ‘[TreeN t]’ Expected type: (t -> a) -> [TreeN t] -> [TreeN a] Actual type: (t -> a) -> TreeN t -> TreeN a
GHC之所以推导出这个奇怪的fmap类型,是因为它看到你把TreeN.fmap f(类型为(t -> a) -> TreeN t -> TreeN a)应用到了children(类型为[TreeN t])上。它试图把TreeN t和[TreeN t]这两个完全不同的类型匹配,自然就抛出了类型不匹配的错误,甚至误以为你要给[TreeN t]这个类型实现Functor实例,所以才会显示错误的fmap绑定类型。
修正后的代码
你需要对列表中的每个TreeN元素单独应用TreeN.fmap f,可以用map(或者因为List本身是Functor,用fmap也一样)来遍历子节点列表:
module TreeN where data TreeN a = LeafN a | ParentN a [TreeN a] deriving (Eq, Show) instance Functor TreeN where fmap f (LeafN x) = LeafN (f x) fmap f (ParentN x children) = ParentN (f x) (map (fmap f) children)
补充说明
map (fmap f) children的作用是:遍历子节点列表children,对每一个TreeN元素递归应用fmap f,这样就能把函数f映射到整个树结构的每一个节点值上。- 不需要显式声明
fmap的类型签名,因为Functor类已经定义了fmap :: (a -> b) -> f a -> f b的通用类型,GHC会自动推导符合要求的具体类型,手动声明反而容易引入额外错误。
内容的提问来源于stack exchange,提问作者James Strieter
相关产品推荐
相关产品推荐

