我正在从“ video”中学习。当然,我要问的问题在本文的主要思想方面还是一个问题,但仍然...
...在第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
似乎只是一个双重功能,即在Free Applicative Functors上定义的函子。根据定义,产品类别由所有可能的有序对象对给定,并且态射也是成对的,因此: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
(通过上面的定义给出)实际上是类别理论所期望的双向/多重功能吗?
P.S。我感到好奇的原因是,似乎{strong>不能通过概括Applicative
进入Functor
,尽管论文指出可以。
答案 0 :(得分:6)
我认为您所采用的范畴理论角度是错误的。有一个Bifunctor类(映射类型为(a -> b) -> (c -> d) -> f a c -> f b d
),但这不是这种概括。如果一个人没有使用某些功能,则fmap2
的签名如下:
fmap2 :: ((a,b) -> c) -> (f a, f b) -> f c
通过考虑fmap2 id
,我们看到我们实现的不是bifunctor,而是笛卡尔函子(即笛卡尔类别之间的单等函子),其中fmap2 id :: (f a, f b) -> f (a,b)
是自然变换:>
然后可以从此Multifunctor
概括中获得适用性。只需将pure
的{{1}}更改为fmap0
的{{1}}。
答案 1 :(得分:2)
让我们从显而易见的内容开始:fmap0
是纯粹的。
您在这里犯了一个错误:fmap2
是liftA2
。
({bimap
非常不同-(a -> b) -> (c -> d) -> f a b -> f c d
)
如果返回到definition of Applicative
,您会看到它具有(<*>)
的默认实现,即liftA2 id
,它允许您以纯净和liftA2
或(<*>)
。
是的,该类等效于Applicative
。