泛化 `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
是纯粹的。
这是你犯了一个错误:fmap2
是 liftA2
。
(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 ($)
。
我正在向“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
是纯粹的。
这是你犯了一个错误:fmap2
是 liftA2
。
(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 ($)
。