一个monad只是endofunctors类别中的一个monoid,这是什么问题?


722

谁先说以下?

一个monad只是endofunctors类别中的一个monoid,这是什么问题?

在一个不太重要的注解上,这是真的吗?如果可以的话,您能否给出一个解释(希望是一个没有太多Haskell经验的人可以理解的解释)?


14
参见“数学
Don Stewart 2010年

18
您无需了解这一点即可在Haskell中使用monad。从实际的角度来看,它们只是通过一些地下管道绕过“州”的聪明方法。
starblue 2010年

1
我也想在这里添加这篇出色的博客文章:stephendiehl.com/posts/monads.html它不能直接回答问题,但是我认为Stephen在Haskell中将类别和单子结合在一起做得非常出色。如果您已阅读以上答案,则应有助于统一两种查看方式。
本·福特

3
更准确地说,“对于任何类别C,其末端信息的类别[C,C]具有由该成分诱导的单面体结构。[C,C]中的单面体对象是C上的单原子。” -来自en.wikipedia.org/wiki/Monoid_%28category_theory%29。有关类别理论中monad的定义,请参见en.wikipedia.org/wiki/Monad_%28category_theory%29。

1
@Dmitry 函子是类别之间的一个函数,有些约束要表现得很好。C类的endofunctor只是C到其自身的函子。Data.FunctorHask类别上的endofunctors的类型类。由于类别由对象和态射组成,因此函子需要同时映射两者。对于Data.Functor的实例f,对象(haskell类型)的映射是f本身,而态射(haskell函数)的映射是fmap。
Matthijs

Answers:


795

詹姆斯·艾里(James Iry)的特别措辞来自他极富娱乐性的《简明,不完整和大部分错误的编程语言史》,他在小说中将其归因于菲利普·沃德勒。

原始报价摘自Saunders Mac Lane 的《工作数学家的类别》,这是类别理论的基础文章之一。在上下文中,这可能是确切了解其含义的最佳位置。

但是,我会刺。原来的句子是这样的:

总而言之,X中的单子仅是X的终结符类别中的一个单义词,乘积×由终结符的组成替换,单位由身份终结符设置。

X这里是一个类别。Endofunctors是从一个类别到其自身的函子(就函数式程序员而言,通常是所有 函子Functor,因为它们主要只处理一个类别;类型的类别,但我离题了)。但是您可以想象另一个类别,即“ X上的 endofunctors ” 类别。这是一个类别,其中的对象是内函子,同态射是自然变换。

在这些终结者中,有些可能是单子。哪一个是单子?在特定意义上恰好是单调的。与其说出从单子到Monoid的确切映射(因为Mac Lane的性能远远超出我的期望),不如将它们各自的定义放在一起,让您进行比较:

一个半身像是...

  • 一套S
  • 的操作,•:S×S→S
  • S的元素,e:1→S

...满足以下法律:

  • (一•B)•C = A•(B•c)中,对于所有的一个bÇ小号
  • Ë•A = A•E =一,所有一个小号

一个单子是...

  • endofunctor T:X→X(在Haskell中,是* -> *带有Functor实例的类型的构造函数)
  • 自然变换μ:T×T→T,其中×表示函子组成(μjoin在Haskell中是已知的)
  • 自然变换η:I→T,其中IX上的恒等符(ηreturn在Haskell中是已知的)

...满足以下法律:

  • μ∘Tμ=μ∘μT
  • μ∘Tη=μηT= 1(恒等式自然转化)

稍作斜视,您也许就能看到这两个定义都是同一抽象概念的实例。


21
感谢您的解释,也感谢“简短,不完整和最错误的编程语言历史”一文。我以为可能是那里。确实是编程幽默中最伟大的作品之一。
罗曼·泰切

6
@乔纳森:在一个id半群的经典表达中,×表示集合的笛卡尔积。您可以在以下网址了解更多信息:en.wikipedia.org/wiki/Cartesian_product,但是基本思想是S×T的元素是一对(s,t),其中s∈St∈T。因此,在此上下文中,单项积的签名•:S×S-> S仅表示一个函数,该函数将S的 2个元素作为输入,并产生S的另一个元素作为输出。
汤姆·克罗基特

12
@TahirHassan-在范畴论的一般性中,我们处理不透明的“对象”而不是集合,因此没有“元素”的先验概念。但是,如果考虑类别Set,其中对象是集合,箭头是函数,则任何集合S的元素都与从任何一个元素集到S的函数一一对应。S的元素e,恰好有一个函数f:1-> S,其中1是任何一个元素集...(续)
Tom Crockett 2012年

12
@TahirHassan 1元素集本身是更广义的类别理论“终端对象”概念的专业化:终端对象是类别中的任何对象,从该对象到其他任何对象都只有一个箭头(您可以检查是否这对于Set中的1个元素集是正确的。在类别理论中,终端对象简称为1。在同构之前,它们是唯一的,因此没有区别它们的意义。所以现在我们有“的元素的纯类别的理论描述小号任何” 小号:他们只是从箭头1小号
汤姆·克罗基特

7
@TahirHassan-要用Haskell的术语来表示,请考虑以下事实:如果S是类型,则编写函数时所能做的f :: () -> S就是挑选某个特定类型的术语S(如果可以的话,选择它的“元素”)并返回它...您未获得有关该参数的实际信息,因此无法更改该函数的行为。因此f必须是一个常数函数,每次都只返回相同的内容。()(“ Unit”)是Hask类别的终端对象,并且恰好有1个(非散度)值存在于其中,这并非巧合。
汤姆·克罗基特

532

凭直觉,我认为幻想的数学词汇是这样说的:

单体

一个monoid是一组对象,以及一种将它们组合的方法。著名的monoid为:

  • 您可以添加的数字
  • 您可以连接的列表
  • 设置可以结合

还有更复杂的例子。

此外,每个 monoid都有一个identity,即将“ no-op”元素与其他元素组合在一起时无效的元素:

  • 0 + 7 == 7 + 0 == 7
  • [] ++ [1,2,3] == [1,2,3] ++ [] == [1,2,3]
  • {} union {apple} == {apple} union {} == {apple}

最后,一个monoid必须是关联的。(只要不改变对象从左到右的顺序,就可以随意减少一长串组合)加法是确定的((5 + 3)+1 == 5+(3+ 1)),但减法不是((5-3)-1!= 5-(3-1))。

单子

现在,让我们考虑一种特殊的集合和一种组合对象的特殊方式。

对象

假设您的集合包含特殊类型的对象:functions。这些函数具有一个有趣的签名:它们不将数字带数字或字符串带字符串。而是,每个函数在两步过程中将数字携带到数字列表中。

  1. 计算0个或更多结果
  2. 以某种方式将这些结果合并为一个答案。

例子:

  • 1-> [1](只需包装输入)
  • 1-> [](丢弃输入,将虚无包装在列表中)
  • 1-> [2](将1加到输入中,然后包装结果)
  • 3-> [4,6](将1加到输入,然后将输入乘以2,然后包装多个结果

组合物件

同样,我们组合功能的方式也很特殊。组合函数的一种简单方法是composition:让我们以上面的示例为例,并使用自身组合每个函数:

  • 1-> [1]-> [[1]](包装输入两次)
  • 1-> []-> [](丢弃输入,将虚无包装在列表中两次)
  • 1-> [2]-> [UH-OH!](我们不能将“ 1”添加到列表中!”)
  • 3-> [4,6]-> [UH-OH!](我们无法添加1个列表!)

不必过多研究类型理论,关键是可以组合两个整数来获得一个整数,但是不能总是组成两个函数并获得相同类型的函数。(类型a-> a的函数 将组成,但类型a-> [a]则不会。)

因此,让我们定义一种不同的功能组合方式。当我们将其中两个功能结合在一起时,我们不想对结果进行“双重包装”。

这是我们的工作。当我们想要组合两个函数F和G时,我们遵循以下过程(称为binding):

  1. 计算F的“结果”,但不要将它们合并。
  2. 分别计算将G应用于F的每个结果的结果,从而得出结果集合。
  3. 展平2级集合并合并所有结果。

回到我们的示例,让我们使用这种“绑定”函数的新方式将一个函数与自身结合(绑定):

  • 1-> [1]-> [1](两次包装输入)
  • 1-> []-> [](丢弃输入,将虚无包装在列表中两次)
  • 1-> [2]-> [3](加1,然后再加1,然后包装结果。)
  • 3-> [4,6]-> [5,8,7,12](将输入加1,然后将输入乘以2,同时保留两个结果,然后对两个结果再次进行所有处理,然后包装最终结果产生清单。)

这种更复杂的功能组合方式关联的(根据您在不进行精美包装时的功能组合是如何关联的)。

绑在一起

  • monad是一种结构,用于定义组合功能(的结果)的方式,
  • 类似于Monoid是一种定义组合对象方式的结构,
  • 如果结合的方法是关联的,
  • 还有一个特殊的“禁止操作”,可以将其与任何事物组合以使事物不变。

笔记

有很多方法可以“包装”结果。您可以列出或设置列表,也可以舍弃除第一个结果以外的所有结果,同时注意是否没有结果,附加状态提示,打印日志消息等。

我在定义上有些松懈,希望可以直观地理解基本思想。

我坚持要求我们的monad对a- > [a]类型函数进行操作,从而简化了某些事情。实际上,monad可以处理a- > mb类型函数,但是泛化只是一种技术细节,并不是主要的见识。


22
这很好地解释了每个monad如何构成一个类别(您要演示的是Kleisli类别,也有Eilenberg-Moore类别)。但是由于您不能组合任何两个Kleisli箭头,a -> [b]并且c -> [d](只能在b=时执行此操作c),因此并不能很好地描述一个类人动物。实际上,它是您描述的展平操作,而不是函数组合,即“ monoid运算符”。
汤姆·克罗基特

6
当然,如果您将monad限制为仅一种类型,即,如果仅允许使用形式的Kleisli箭头,则a -> [a]这将是一个monoid(因为您将Kleisli类别简化为单个对象,而任何类别都只有一个对象从定义上讲是一个monoid!),但它不能捕获monad的全部一般性。
汤姆·克罗基特

5
最后一点,请记住--[a]只是-> [] a。([]也是类型构造函数。)因此,它不仅可以看作是-> mb,而且[]确实是Monad类的实例。
Evi1M4chine 2013年

8
这是我在数周内遇到的有关monad以及它们的monoid的数学背景的最佳,最古怪的解释。这是每本Haskell书中应印有的有关单子的内容。赞!也许可以进一步获得一条信息,即monads是作为参数化的typeclass实例实现的,该实例将haskell中放入它们的内容包装到了帖子中。(至少这是我现在明白他们纠正我,如果我错了,请参阅。haskell.org/haskellwiki/What_a_Monad_is_not
sjas

1
这太棒了-这是我已经足够理解的唯一解释,可以向其他人解释...但是我仍然不明白为什么这是思考任何事情的宝贵方法。:(
Adam Barnes

84

首先,我们将要使用的扩展和库:

{-# LANGUAGE RankNTypes, TypeOperators #-}

import Control.Monad (join)

其中,RankNTypes是唯一对以下内容绝对必要的内容。我曾经写过一篇关于RankNTypes有些人似乎发现有用的解释,所以我将参考它。

引用汤姆·克罗基特的出色答案,我们有:

一个单子是...

  • 一个endofunctor,T:X-> X
  • 自然变换μ:T×T-> T,其中×表示函子组成
  • 自然变换η:I-> T,其中IX上的恒等endofunctor

...满足以下法律:

  • μ(μ(T×T)×T))=μ(T×μ(T×T))
  • μ(η(T))= T =μ(T(η))

我们如何将其转换为Haskell代码?好吧,让我们从自然转换的概念开始:

-- | A natural transformations between two 'Functor' instances.  Law:
--
-- > fmap f . eta g == eta g . fmap f
--
-- Neat fact: the type system actually guarantees this law.
--
newtype f :-> g =
    Natural { eta :: forall x. f x -> g x }

A型的形式的f :-> g类似于一个功能类型,但是代替它想作为一个功能两者类型(种*),认为它作为一个态射两者之间函子(各种* -> *)。例子:

listToMaybe :: [] :-> Maybe
listToMaybe = Natural go
    where go [] = Nothing
          go (x:_) = Just x

maybeToList :: Maybe :-> []
maybeToList = Natural go
    where go Nothing = []
          go (Just x) = [x]

reverse' :: [] :-> []
reverse' = Natural reverse

基本上,在Haskell中,自然变换是某种类型的函数 f x到另一种类型g x,使得x类型变量为“不可访问”给调用者。因此,例如,sort :: Ord a => [a] -> [a]不能将其转换为自然变换,因为它对于我们可以实例化的类型是“挑剔的” a。我经常想到的一种直观方法是:

  • 函子是一种在不触及结构的情况下操作某物内容方法
  • 自然的转变是在 无需触摸或查看内容即可对事物结构

现在,让我们解决这个定义的子句。

第一个子句是“ endofunctor,T:X-> X”。嗯,FunctorHaskell中的每个对象都是人们所说的“ Hask类别”的终结者,其对象是Haskell类型(种类*),其态射是Haskell函数。这听起来像是一个复杂的陈述,但实际上是一个非常琐碎的陈述。它的全部意思是a Functor f :: * -> *提供了构造类型的方法f a :: *为任何对象a :: *fmap f :: f a -> f b从任何对象函数的方法f :: a -> b,并且这些方法均服从函子定律。

第二条: Identity Haskell中仿函数(随平台提供,因此您只需导入即可)是按以下方式定义的:

newtype Identity a = Identity { runIdentity :: a }

instance Functor Identity where
    fmap f (Identity a) = Identity (f a)

因此,可以将汤姆·克罗基特定义中的自然变换η:I-> T编写为任何Monad实例t

return' :: Monad t => Identity :-> t
return' = Natural (return . runIdentity)

第三条款:Haskell中两个函子的组成可以通过这种方式定义(这也随平台一起提供):

newtype Compose f g a = Compose { getCompose :: f (g a) }

-- | The composition of two 'Functor's is also a 'Functor'.
instance (Functor f, Functor g) => Functor (Compose f g) where
    fmap f (Compose fga) = Compose (fmap (fmap f) fga)

因此自然变换μ:T×T-> T,Tom Crockett定义中可以这样写:

join' :: Monad t => Compose t t :-> t
join' = Natural (join . getCompose)

声明这是endofunctors类别中的一个monoid,则意味着Compose(部分地仅应用于它的前两个参数)是关联的,这Identity就是它的标识元素。即,以下同构成立:

  • Compose f (Compose g h) ~= Compose (Compose f g) h
  • Compose f Identity ~= f
  • Compose Identity g ~= g

这些都很容易证明,因为ComposeIdentity都定义为newtype,Haskell报告将的语义定义newtype为要定义的类型与newtype数据构造函数的参数类型之间的同构。因此,例如,让我们证明Compose f Identity ~= f

Compose f Identity a
    ~= f (Identity a)                 -- newtype Compose f g a = Compose (f (g a))
    ~= f a                            -- newtype Identity a = Identity a
Q.E.D.

在新类型中Natural,我无法弄清楚(Functor f, Functor g)约束在做什么。你能解释一下吗?
dfeuer

@dfeuer它实际上并没有做任何必要的事情。
路易斯·卡西利亚斯

1
@LuisCasillas我删除了那些Functor约束,因为它们似乎没有必要。如果您不同意,请随时将其添加回去。
Lambda Fairy'3

您能否详细说明将函子的产品视为组合物的正式含义?特别是,函子组成的投影形态是什么?我的猜测是,仅针对函子F对其自身定义F x F,并且仅在join定义时才定义。那join就是投影态射。但是我不确定。
tksfz 2015年

6

注意:不,这是不正确的。在某个时候,丹·皮波尼本人对此回答发表了评论,说这里的因果正好相反,他写这篇文章是为了回应詹姆斯·伊里的怪癖。但是它似乎已经被删除了,也许是由于一些强迫性的手段。

以下是我的原始答案。


Iry很有可能读过《从Monoids到Monads》一书,其中Dan Piponi(sigfpe)在Haskell中从monoids派生了monads,他对类别理论进行了很多讨论,并明确提到了“ Hask上的终结者的类别”。无论如何,任何想知道单子组成为内爆者类中的类群的意义的人都可以从阅读此推导中受益。


1
“也许是一些强迫性的手段”-或者,正如我们在本网站上亲切提及的那样,是主持人:-)
Halfer '18

6

我通过更好地理解Mac Lane的《为数学家分类理论》中的臭名昭著的推论而来这篇文章。

在描述什么是事物时,描述它不是事物通常同样有用。

Mac Lane使用描述来描述Monad的事实,可能暗示它描述了Monad独有的东西。忍受我。为了使人们对这一说法有更广泛的了解,我认为需要明确指出他不是描述单子论所独有的东西。该声明除其他外同样描述了Applicative和Arrows。出于相同的原因,我们可以在Int上拥有两个单半体(Sum和Product),在endofunctors类别中,我们可以在X上具有多个单半体。但是更多的相似之处。

Monad和Applicative均符合以下条件:

  • endo =>在同一位置开始和结束的任何箭头或形态
  • functor =>两个类别之间的任何箭头或态射

    (例如,每天Tree a -> List b,但在类别中Tree -> List

  • monoid =>单个对象;即单一类型,但在这种情况下,仅关于外部层;所以,我们不能Tree -> List只有List -> List

该语句使用“ ...的类别”。它定义了语句的范围。作为一个例子,该函子类别描述的范围f * -> g *,即Any functor -> Any functor,例如,Tree * -> List *Tree * -> Tree *

分类语句未指定的内容描述了在哪里允许一切

在这种情况下,在函子内部未指定* -> *aka a -> b,即Anything -> Anything including Anything else。当我的想象力跳到Int-> String时,它也包含Integer -> Maybe Int,甚至是Maybe Double -> Either String Intwhere a :: Maybe Double; b :: Either String Int

因此,该语句如下:

  • 函子范围 :: f a -> g b(即,任何参数化类型到任何参数化类型)
  • 内函数+函子:: f a -> f b(即,任何一种参数化类型都属于相同的参数化类型)...表示不同,
  • endofunctor类别中的一个monoid

那么,这种构造的力量在哪里?为了欣赏完整的动态效果,我需要看到一个monoid的典型图形(带有类似标识箭头的单个对象:: single object -> single object)无法说明我被允许使用参数化为任意数量的monoid 的箭头,从Monoid中允许的一种类型对象。等价的内向〜身份箭头定义忽略了函子的类型值以及最内部的“有效负载”层的类型和值。因此,等价true在函数类型匹配的任何情况下返回(例如,Nothing -> Just * -> Nothing等同于Just * -> Just * -> Just *因为它们都是Maybe -> Maybe -> Maybe)。

补充工具栏:〜外面是概念上的,但是中最左边的符号f a。它还描述了“ Haskell”首先读入的内容(大图);所以相对于类型值,类型是“外部”。编程中各层之间的关系(参考链)在类别中不容易关联。集的类别用于描述类型(整数,字符串,也许是整数等),其中包括函子的类别(参数化类型)。参考链:函子类型,函子值(该函子集合的元素,例如Nothing,Just),以及每个函子值所指向的所有其他内容。在类别中,对关系的描述不同,例如,return :: a -> m a被认为是从一个函子到另一个函子的自然变换,与迄今为止提到的任何事物都不同。

回到主线程,总而言之,对于任何定义的张量积和中性值,该语句最终都描述了一个由其自相矛盾的结构产生的惊人强大的计算结构:

  • 在外部,它表现为单个对象(例如:: List);静态的
  • 但在内部,允许很多动态
    • 与任何Arity函数的饲料相同类型的任意数量的值(例如,Empty |〜NonEmpty)。张量积将把任何数量的输入减少为一个单一值...对于外部层(〜fold关于有效负载什么也没说)
    • 的无限范围为最内层的类型和值

在Haskell中,阐明声明的适用性很重要。这种结构的强大功能和多功能性与monad 本身完全无关。换句话说,该构造不依赖于使monad唯一的原因。

当试图确定是否要使用共享上下文构建代码以支持相互依赖的计算以及可以并行运行的计算时,此臭名昭著的陈述(尽管描述得如此之多)与选择以下内容没有区别。适用性,“箭头”和“单声道”,而是描述它们多少相同。对于眼前的决定,该声明尚无定论。

这经常被误解。该语句继续被描述join :: m (m a) -> m a为单项内泛函的张量积。但是,它没有阐明在本声明的上下文中(<*>)还应该如何选择。这确实是六分之二的例子。组合值的逻辑是完全相同的。相同的输入会从每个输入产生相同的输出(与Int的Sum和Product单面体不同,因为在组合Ints时它们会产生不同的结果)。

因此,回顾一下:endofunctors类别中的一个monoid描述:

   ~t :: m * -> m * -> m *
   and a neutral value for m *

(<*>)并且(>>=)既提供对两个同时访问m,以便计算所述单个返回值的值。用于计算返回值的逻辑是完全相同的。如果不是因为他们参数(该功能的不同形状f :: a -> bk :: a -> m b)和参数与计算相同的返回类型的位置(即a -> b -> bb -> a -> b每一个分别的),我想我们可以在参数化monoidal的逻辑,张量积,可在两个定义中重用。作为一个练习,使点,尝试和实施~t,以及你结束了(<*>)(>>=)取决于你决定如何定义它forall a b

如果我的最后一点在概念上至少是对的,那么它将解释Applicative和Monad之间的精确且仅有计算上的区别:它们对函数进行参数化。换句话说,不同的是外部对这些类型的类的实现。

总而言之,以我自己的经验,Mac Lane的臭名昭著的报价提供了一个很棒的“ goto”模因,这是我在浏览类别以更好地理解Haskell中使用的成语时可以参考的指南。它成功地捕获了可在Haskell中完美访问的强大计算能力的范围。

但是,具有讽刺意味的是,我是如何首先误解了该声明在monad之外的适用性,以及我希望在此传达的内容。它描述的所有内容在Applicative和Monad(以及Arrows等)之间是相似的。它没有说的只是它们之间很小但有用的区别。

-E


5

这里的答案在定义monoid和monad方面做得非常出色,但是,它们似乎仍然无法回答这个问题:

在一个不太重要的注解上,这是真的吗?如果可以的话,您能否给出一个解释(希望是一个没有太多Haskell经验的人可以理解的解释)?

这里遗漏的问题的症结在于“ monoid”的不同概念,更准确地说是所谓的分类 -在monoidal类别中的monoid。可悲的是,Mac Lane的书本身使人非常困惑

总而言之,in中的monad X只是endofunctors类别中的一个monoid X,乘积×由endofunctors的组成代替,单位由endofunctor标识设置。

主要困惑

为什么这令人困惑?因为它没有定义的“ endofunctors类别中的monoid” X。取而代之的是,这句话建议将所有endofunctors集合内一个类半群与函子组成一起作为二元运算,将身份函子作为一个单半群单元。它工作得非常好,并且可以将包含身份函子且在函子组成下封闭的endofunctors的任何子集变成一个monoid。

但这并不是正确的解释,这本书在那个阶段还没有弄清楚。一个Monad f固定的 endofunctors,而不是根据组成封闭的endofunctors的子集。一种常见的结构是使用f产生通过取该组所有的幺半k倍的组合物f^k = f(f(...))f与本身,包括k=0对应于身份f^0 = id。现在S,所有这些所有权力的集合k>=0确实是一个mono半同形的“乘积×被终结者组成,单位由身份终结者所设定”。

但是:

  • S可以为任何函子定义此monoid ,f甚至可以为的任何自映射定义该monoid X。这是由生成的类集f
  • S由函子组成和恒等函子给定的单曲面结构与f是否为单子无关。

为了使事情更加混乱,您可以从目录中看到“单曲面类别中的Monoid”的定义。但是,理解这一概念对于理解与monad的联系绝对至关重要。

(严格)单项类别

要第七章幺(后来自带比第六章上单子),我们发现了所谓的定义严格monoidal范畴作为三重(B, *, e),其中B是一个类别,*: B x B-> B一个bifunctor(函子相对于与其他组件的每个部件固定),e是中的单位对象B,满足关联性和单位定律:

(a * b) * c = a * (b * c)
a * e = e * a = a

对于任何物体a,b,cB,而对于任何态射相同身份a,b,ce替换id_e的身份,同态e。现在B具有启发性的观察结果是,在我们感兴趣的情况下,X以自然变换为态素*的函子类,函子组成和e身份函子的类别满足所有这些定律,可以直接验证。

这本书中的定义是“松弛” 单项类的定义,其中法律仅对满足所谓相干关系的某些固定自然变换进行模运算,但是这对于我们的终结论者类而言并不重要。

id面体类别中的面体

最后,在第七章的第3节“ Monoids”中,给出了实际的定义:

阿半群c在monoidal范畴(B, *, e)是的目的B有两个箭头(态射)

mu: c * c -> c
nu: e -> c

使3个图可交换。回想一下,在我们的案例中,这些是endofunctors类别中的态射,这是joinreturnmonad 精确对应的自然变换。当我们使组合物的连接变得更加清晰*更加明确,取代c * c通过c^2,这里c是我们的单子。

最后,请注意,为一般(非严格)单曲面类别编写了3个交换图(按单曲面类别中的单曲面定义),而在我们的情况下,作为单曲面类别的一部分出现的所有自然变换实际上都是恒等式。这将使这些图与monad定义中的图完全相同,从而使对应关系完整。

结论

总之,根据定义,任何monad都是endofunctor,因此是endofunctors类别中的一个对象,其中monadic joinreturn运算符满足该特定(严格)monoidal类别的monoid的定义。反之亦然,根据定义,endofunctors的monoidal类别中的任何monooid都是由(c, mu, nu)一个对象和两个箭头组成的三元组,例如,在我们的情况下为自然变换,满足与monad相同的定律。

最后,请注意(经典)monoid和更简单的monoidal类中的monoid之间的主要区别。两个箭头munu以上是不再在一组二进制运算和一单元。相反,您有一个固定的endofunctor c*尽管书中的说法令人困惑,但仅函子组成和身份函子无法提供monad所需的完整结构。

另一种方法是与C集合中所有自映射的标准monoid比较A,其中二进制运算是组合,可以看到将标准笛卡尔积映射C x CC。传递给归类的monoid,我们用x函子组成替换笛卡尔乘积*,并且二元运算被替换为自然转换muc * cc,即join运算符的集合

join: c(c(T))->c(T)

对于每个对象T(编程中的类型)。可以用固定的单点集的地图图像标识的经典类四面体中的标识元素,由return运算符集合代替

return: T->c(T) 

但是现在不再有笛卡尔积,因此没有元素对,因此也没有二进制运算。


那么,您对问题“这是真的”部分的答案是什么?一元论在endofunctors类别中是否是一个monoid,这是真的吗?如果是的话,则一个单物组和一个代数单物组(一个具有相乘和一个单位的集合)的范畴论概念之间的关系是什么?
亚历山大·贝洛波尔斯基
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.