“应用函子上的幺半群”与“endofunctor类别中的幺半群”有什么不同?

时间:2018-04-24 18:46:45

标签: monads functor applicative category-theory monoids

这些陈述或许都不是绝对精确的,但是monad通常被定义为“endofunctors类别中的monoid”; Haskell Alternative被定义为“应用仿函数上的一个幺半群”,其中applicative functor是一个“强疏松的幺正函子”。现在这两个定义听起来非常类似于无知(我),但工作方式有很大不同。替代的中性元素具有类型f a,因此是“空”,并且对于monad具有类型a -> m a,因此具有“非空”的意义;替代的操作具有类型f a -> f a -> f a,并且monad的操作具有类型(a -> f b) -> (b -> f c) -> (a -> f c)。在我看来,真正重要的细节是在endofunctors 类别 over endofunctors ,尽管替代方案中的“强松弛”细节可能很重要;但这就是我感到困惑的地方,因为至少在Haskell中,monads最终成为替代品:我发现我还没有对这里的所有细节进行精确的分类理解。

如何精确地表达替代和monad之间的区别,使得它们都是与endofunctors相关的幺半群,然而一个具有“空”中性而另一个具有“非空”中性元素?

3 个答案:

答案 0 :(得分:19)

通常,幺半群是在幺半群类别中定义的,幺半群类别是定义对象和单位对象的某种(张量)乘积的类别。

最重要的是,类型的类别是单一的:类型ab的乘积只是一种对(a, b),单位类型是()

然后将一个幺半群定义为具有两个态射的对象m

eta :: () -> m
mu  :: (m, m) -> m

请注意,eta只选择m的元素,因此它等同于mempty,并且curry mu变为mappend通常的Haskell Monoid类。

这是一类类型和功能,但也有一个单独的endofunctors和自然转换类别。它也是一个幺半群类别。两个仿函数的张量积被定义为它们的组合Compose f g,而unit是身份仿函数Id。该类别中的幺半群是monad。和以前一样,我们选择一个对象m,但现在它是一个endofunctor;和两个态射,现在是自然变换:

eta :: Id ~> m
mu  :: Compose m m ~> m

在组件中,这两个自然变换成为:

return :: a -> m a
join :: m (m a) -> m

应用仿函数也可以被定义为仿函数类别中的幺半群,但是具有称为日卷积的更复杂的张量积。或者,等效地,它可以被定义为(松散地)保留幺半群结构的仿函数。

Alternative是类型(不是endofunctors)类别中的幺半群。此系列由应用仿函数f生成。对于每种类型a,我们都有一个幺半群,其memptyf a的元素,其mappendf a对映射到f a的元素。这些多态函数称为empty<|>

特别是,empty必须是多态值,这意味着每种类型a都有一个值。例如,这可能是列表仿函数,其中空列表在a中是多态的,或者对于具有多态值Maybe的{​​{1}}。请注意,这些都是具有不依赖于类型参数的构造函数的多态数据类型。直觉是,如果您将仿函数视为容器,则此构造函数会创建并清空容器。空容器是自动多态的。

答案 1 :(得分:4)

这两个概念都与“幺半群”类别&#34;的概念联系在一起,这是一个类别,你可以定义一个幺半群的概念(和某些其他类型的代数结构)。您可以将monoidal类别视为: category 定义一个参数的函数的抽象概念; monoidal类定义零参数或多个参数的函数的抽象概念。

monad是endofunctors类别中的monoid;换句话说,它是一个幺半群,其中产品(2个参数的函数)和身份(0个参数的函数)使用由特定(奇异)幺半群类别(幺半群)定义的多参数函数的概念终结者和组成的类别)。

应用仿函数是一个幺正仿函数。换句话说,它是一个保留了幺半群类别的所有结构的仿函数,而不仅仅是使它成为一个类别的部分。很明显,这意味着它具有mapN函数,用于具有任意数量参数的函数,而不仅仅是一个参数的函数(就像普通仿函数一样)。

所以monad在中存在特定的monoidal类别(恰好是endofunctors的类别),而applicative functor在两个monoidal类别之间映射(恰好属于同一类别,因此它是一种终结者。)

答案 2 :(得分:1)

用一些Haskell代码补充其他答案,这是我们如何表示Day卷积单项式结构@Bartosz Milewski所指:

data Day f g a = forall x y. Day (x -> y -> a) (f x) (g y)

单元对象为函子Identity

然后我们可以将应用类重新定义为关于此单调式结构的单调式对象:

type f ~> g = forall x. f x -> g x
class Functor f => Applicative' f
  where
  dappend :: Day f f ~> f
  dempty :: Identity ~> f

您可能会注意到这种现象与其他熟悉的类人动物对象的韵律如何:

class Functor f => Monad f
  where
  join :: Compose f f ~> f
  return :: Identity ~> f

或:

class Monoid m
  where
  mappend :: (,) m m -> m
  mempty :: () -> m

斜视一下,您也许还可以看到dappend只是liftA2的包装版本,同样也是dempty的{​​{1}}的包装版本。