为什么类型类Functor
只有成员fmap
?我经常发现执行折叠数据类型很有用。比如说,分层的,就像一棵树。
请注意,map
是fold
的特例,即后者更为基础。我想我可以采取它的方式,但也许有一个原因?
答案 0 :(得分:12)
因为Functor
是一种非常普遍的对象;并非所有Functor
支持折叠。例如,有一个实例 1
instance Functor (a ->) where
-- > fmap :: (b -> c) -> (a -> b) -> (a -> c)
fmap f g = g . f
但是,虽然(a ->)
对于所有Functor
来说都是a
,但对于无限a
,并没有合理的fold
定义。 (顺便说一句,'折叠通常是catamorphism,这意味着它对每个仿函数都有不同的类型。Foldable
类型类为序列类型定义它。)
考虑foldr
的{{1}}定义是什么样的;最外层的应用程序是什么?
Integer -> Integer
是? foldr (\ _ n -> 1 + n) 0 (\ n -> n + 1)
没有合理的定义,在参数类型上没有更多的结构。
1 fold
并非合法的Haskell。但我仍然会使用它作为(a ->)
的更易阅读的版本,因为我觉得新手更容易理解。
答案 1 :(得分:6)
您正在寻找的抽象是Foldable
:这是一个类型类,提供fold
的各种形式。
对于可以“更改时折叠”的内容,还有Traversable
,与列表的mapAccumL
功能相当。
fmap
实际上并不是fold
的特殊情况,正如@DietrichEpp所指出的那样,请看possible non-Functor instances of Foldable。
map
是mapAccumL
的一个特例(给出名称并不奇怪),因此Traversable
的定义要求该事物也是Functor
和Foldable
。