Haskell自定义数据类型Arf的Functor实例实现疑问
首先先修正你提供的示例代码里的两处笔误,修正后的代码才是可正常运行的正确版本:
instance Functor Arf where fmap f (Ser x xs) = Ser (f x) (map (fmap f) xs)
笔误说明:
- 原代码里
fmap f [] = []是无效冗余代码,Arf类型只有Ser这一个构造器,不存在列表的[]构造器,模式匹配永远不会走到这一分支 - 原代码里
Ser x xs的模式匹配中,你误把第二个字段xs写成了x,属于变量名输入错误
核心问题解答
你提到的两种写法的本质差异是类型不匹配,我们拆解各部分类型就非常好理解:
- 先明确
Ser构造器的字段类型:Ser :: a -> [Arf a] -> Arf a,第二个字段是元素类型为Arf a的列表 - 我们要实现的
fmap :: (a -> b) -> Arf a -> Arf b的作用是,把Arf结构里所有的a类型值都转成b类型,同时保持结构不变 - 对于
Ser的第二个字段xs :: [Arf a],我们需要把列表里每个Arf a元素都转成Arf b,才能得到符合要求的[Arf b]传给新的Ser构造器
- 如果写
fmap f xs:列表本身的Functor实例会尝试对列表里每个Arf a元素直接应用f :: a -> b,但f根本不能接收Arf a类型的参数,类型校验直接失败,编译报错 - 如果写
map (fmap f) xs:map是列表的遍历函数,对列表里每个Arf a元素应用Arf类型的fmap f,刚好能把每个Arf a递归转换为Arf b,类型完全匹配,逻辑也符合递归遍历嵌套结构的需求
举个实际运行的例子方便理解:
我们定义一个Arf Int类型的值:
demoVal :: Arf Int demoVal = Ser 1 [Ser 2 [], Ser 3 [Ser 4 []]]
执行fmap (+1) demoVal的结果是:
Ser 2 [Ser 3 [], Ser 4 [Ser 5 []]]
可以看到整个嵌套结构里的所有Int值都加了1,结构完全保留,这就是map (fmap f)递归遍历的效果。
内容的提问来源于stack exchange,提问作者sinNombre
相关产品推荐
相关产品推荐

