理解应用函子的关键是弄清楚它们保留什么结构。
正则函子保留了基本的分类结构:它们映射类别之间的对象和态射,并且它们保留了类别的规律(关联性和同一性)。
但是一个类别可能有更多的结构。例如,它可能允许定义类似于态射但采用多个参数的映射。这种映射是通过柯里化定义的:例如,两个参数的函数被定义为一个参数返回另一个函数的函数。如果您可以定义一个表示函数类型的对象,这是可能的。通常,这个对象被称为指数对象(在 Haskell 中,它只是类型b->c)。然后我们可以有从一个对象到指数的态射,并将其称为双参数态射。
Haskell 中应用函子的传统定义是基于多个参数的映射函数的思想。但是有一个等价的定义可以将多参数函数沿不同的边界分割。您可以将这样的函数视为 product(Haskell 中的一对)到另一种类型(此处为 c)的映射。
a -> (b -> c) ~ (a, b) -> c
这使我们可以将应用函子视为保留产品的函子。但产品只是所谓的单曲面结构的一个例子。
一般来说,幺半群类别是配备张量积和单位对象的类别。例如,在 Haskell 中,这可能是笛卡尔积(一对)和单位类型 ()。但是请注意,单曲面定律(结合律和单位定律)仅在同构之前有效。例如:
(a, ()) ~ a
然后可以将应用函子定义为保留单曲面结构的函子。特别是,它应该保护单位和产品。我们是否在应用函子之前或之后进行“乘法”并不重要。结果应该是同构的。
然而,我们并不真正需要一个成熟的幺半群函子。我们所需要的只是两个态射(与同构相反)——一个用于乘法,一个用于单位。这种半保留幺半体结构的函子称为松散的幺半体函子。因此,替代定义:
class Functor f => Monoidal f where
unit :: f ()
(**) :: f a -> f b -> f (a, b)
很容易证明Monoidal 等价于Applicative。例如,我们可以从unit 得到pure,反之亦然:
pure x = fmap (const x) unit
unit = pure ()
应用定律仅遵循幺半群定律(结合律和单位定律)。
在范畴论中,单曲面结构的保存与张量强度有关,因此应用函子也称为强松散单曲面函子。但是,在 Hask 中,每个函子都具有关于乘积的规范强度,因此该属性不会在定义中添加任何内容。
现在,如果您熟悉将 monad 定义为内函子类别中的幺半群,您可能有兴趣知道应用程序同样是内函子类别中的幺半群,其中张量积是 Day卷积。但这很难解释。