Haskell 若可以使用可折叠定义映射,那个么为什么在可折叠的定义中并没有提到函子呢

Haskell 若可以使用可折叠定义映射,那个么为什么在可折叠的定义中并没有提到函子呢,haskell,functor,foldable,Haskell,Functor,Foldable,我读到,map可以使用foldr定义,即它是一个基本的递归函数。至少对于列表 现在我的问题是:为什么函子不是可折叠的子类型类?如果fmap只能用列表的foldr来定义,那么它们有什么特别之处呢 使用foldr查看map的定义: myMap f xs = foldr step [] xs where step x ys = f x : ys 我可以使用幺半群来实现: myMap f xs = foldr step mempty xs where step x ys = f x :

我读到,
map
可以使用
foldr
定义,即它是一个基本的递归函数。至少对于列表

现在我的问题是:为什么函子不是可折叠的子类型类?如果
fmap
只能用列表的
foldr
来定义,那么它们有什么特别之处呢

使用foldr查看
map
的定义:

myMap f xs = foldr step [] xs
    where step x ys = f x : ys
我可以使用幺半群来实现:

myMap f xs = foldr step mempty xs
    where step x ys = f x : ys
但可悲的是,我还不足以成为哈斯凯尔的魔术师,无法逃脱
cons

但可悲的是,我还不足以成为哈斯凯尔的魔术师,因此无法逃脱罪犯的惩罚

你已经发现了一个根本性的问题,即不允许把每一个可折叠的函数都变成函子
foldr
放弃折叠的结构,只保留(相当于)其元素的列表。你不能“避开缺点”,因为你不知道数据的结构是什么,只给了一个
可折叠的
实例

鉴于树的这一(典型)定义:

data Tree a = Bin a (Tree a) (Tree a) | Tip

instance Functor Tree where
  fmap f (Bin a l r) = Bin (f a) (fmap f l) (fmap f r)
  fmap _ Tip = Tip

instance Foldable Tree where
  foldMap f (Bin a l r) = foldMap f l <> f a <> foldMap f r
  foldMap _ Tip = mempty

这两棵树都有一个“ab”的
toList
,但明显不同。这意味着折叠树的行为会丢失一些无法恢复的信息(即左子树、右子树和元素之间的边界)。由于无法使用可折叠的
实例的结果来区分x和y,因此无法仅使用这些方法编写
fmap
,从而
fmap id==id
。我们不得不求助于模式匹配,并使用构造函数写出
Functor
实例。

为什么要这样做?这只是一个愚蠢的想法。另一方面,Functor和Foldable不是类型,Haskell中也没有子类型。
IO
是一个Functor。假设有一个
x=readLn::IO Int
foldr(+)0 x
必须是
Int
。这是什么?@Ingo那么你如何称呼
Applicative
Functor
之间的关系呢。只是“每个
应用程序
都必须是
Functor的实例
”,它是类型类,而不是类型,因此是超级/子类。
可折叠的
太以列表为中心了,它基本上允许一个人高效地运行
foldr f x。toList
。它不会区分具有相同顺序的树。相反,
fmap f
将保留所有树结构。
let x = Bin 'b' (Bin 'a' Tip Tip) Tip
let y = Bin 'a' Tip (Bin 'b' Tip Tip)