泛化 `Functor` class 成为 `MultiFunctor`?

Generalization of the `Functor` class to become a `MultiFunctor`?

我正在向“Free Applicative Functors”学习。当然,我要问的问题有点偏离论文的主要思想,但仍然...

...在第 6 页上尝试将 Functor 概括为 MultiFunctor:

class Functor f ⇒ MultiFunctor f where
    fmap0 :: a → f a
    fmap1 :: (a → b) → f a → f b
    fmap1 = fmap
    fmap2 :: (a → b → c) → f a → f b → f c
    ...

我看不出这个定义从范畴论的角度是如何合理的:fmap2 似乎只是一个双函子,即定义在 product category 上的函子。根据定义,产品类别由所有可能的有序对象对给出,态射也是对,因此:fmap2 :: (a -> a', b -> b') -> (f a, f b) -> (f a', f b') 看起来和感觉更合适的签名。

我可以理解 (a -> b -> c) -> f a -> f b -> f c 选择背后的思考方式:这是采用已知 (a -> b) -> f a -> f b 签名并强制其使用二进制函数而不是一元函数的最明显方法.但是MultiFunctor(由上面的定义给出)实际上是范畴论所期望的bi-/multifunctor吗?

P.S。我很好奇的原因是似乎 不能 通过概括 Functor 达到 Applicative,尽管论文指出可以。

让我们从显而易见的开始:fmap0 是纯粹的。

这是你犯了一个错误:fmap2liftA2

(bimap 非常不同 - (a -> b) -> (c -> d) -> f a b -> f c d)

如果你回到 definition of Applicative,你会看到它有一个 (<*>) 的默认实现,即 liftA2 id,它允许你根据pure 和 liftA2(<*>).

所以是的,class 等同于 Applicative

我认为你所采取的范畴论角度是错误的。有一个 Bifunctor class(带有 (a -> b) -> (c -> d) -> f a c -> f b d 类型的映射),但这不是这个概括。如果对某些函数进行 uncurry,那么 fmap2 的签名如下所示:

fmap2 :: ((a,b) -> c) -> (f a, f b) -> f c

并且通过考虑 fmap2 id,我们看到我们正在实现的不是双函子而是笛卡尔函子(即笛卡尔类别之间的幺半群函子),fmap2 id :: (f a, f b) -> f (a,b) 是自然变换:

然后可以从这个 Multifunctor 概括中得到应用。只需将 pure 更改为 fmap0,将 (<*>) 更改为 fmap2 ($)