【问题标题】:Does the term "monad" apply to values of types like Maybe or List, or does it instead apply only to the types themselves?术语“monad”是否适用于 Maybe 或 List 等类型的值,还是仅适用于类型本身?
【发布时间】:2012-06-16 21:57:29
【问题描述】:

我注意到“monad”这个词的使用方式似乎有些不一致。我开始相信这是因为那里的许多(如果不是大多数)monad 教程是由刚刚开始自己​​弄清楚 monad 的人编写的(例如:核废料太空服卷饼),所以这个学期结束了有点过载/损坏。

特别是,我想知道术语“monad”是否可以应用于诸如 Maybe、List 或 IO 等类型的单个值,或者术语“monad”是否真的应该仅应用于类型本身。

这是一个微妙的区别,所以也许一个类比可能会更清楚。在数学中,我们有环、场、群等。这些术语适用于整个值集以及可以对它们执行的操作,而不是单个元素。例如,整数(连同加法、否定和乘法运算)形成一个环。你可以说“整数是一个环”,但你永远不会说“5 是一个环”。

那么,你能说“Just 5 是一个单子”,还是说“5 是一个环”是错误的?我不知道范畴论,但我的印象是说“Maybe 是一个单子”而不是“Just 5 是一个单子”才有意义。

【问题讨论】:

  • 如果您了解一些代数,请阅读范畴论。它甚至可能会让您感兴趣。
  • @AlexandreC。我读过一些关于范畴论的书,虽然还没有找到一个好的介绍。有什么建议么?关于该主题的维基百科页面似乎是在假设读者已经理解类别理论的情况下编写的。特别让我感到困惑的一件事是类别具有“对象集合”的陈述。什么是“收藏”?一套?还有什么?
  • CT 的问题在于它太抽象了,你必须随身携带自己的例子。您会在任何关于代数几何(或交换代数)的良好入门课程、一些计算机科学课程、一些几何课程等中找到工作知识。This 似乎对计算机科学的观点很有希望。标准书是 MacLane 的工作数学家的范畴理论。另外,请阅读Sigfpe's blog
  • I wrote about this same problem a couple of years ago. 我建议monadic类型的值可以称为“motes”。
  • 请注意,这里可能会出现另一层混乱。你说Just 5 不是单子是对的,Maybe 是。但同样需要指出的是,Just 5Maybe Integer 的类型也不是 Monad。

标签: terminology monads


【解决方案1】:

“Monad”(和“Functor”)通常被误用来描述值。 没有值是 monad、functor、monoid、applicative functor 等。 只有类型和类型构造函数(更高级的类型)可以。 当你听到(你会听到)“列表是幺半群”或“函数是单子”等,或者“这个函数需要一个单子作为参数”时,不要相信它。 问演讲者“考虑到 Haskells 类对 types(包括高阶类型)而不是值进行分类,任何值怎么可能是 monoid(或 monad 或 ...)? 列表不是幺半群(等)。 List a 是。

我的猜测是,这种流行的误用源于具有值类而不是类型类的主流语言,因此习惯性的、无意识的值类思维潜入其中。

为什么我们是否准确地使用语言很重要? 因为我们用语言思考,我们通过语言建立和传达理解。 所以为了有清晰的想法,有清晰的语言是有帮助的(或者能够随时)。

“我们语言的邋遢让我们更容易产生愚蠢的想法。关键是这个过程是可逆的。” - 乔治·奥威尔,《政治与英语》

编辑:这些评论适用于 Haskell,而不适用于更一般的范畴论设置。

【讨论】:

  • 可以说“列表产生一个幺半群”吗?
  • 更准确地说,存在一个以 List 作为其载体的 monoid/monad/whatever,因为通常在同一个载体上存在许多这样的代数结构。
  • @MauricioScheffer 我只想说“List a 是一个幺半群”(对于所有 a)和“List 是一个仿函数/应用程序/单子”。
  • “为什么我们是否准确地使用语言很重要?”我完全同意,这就是我问这个问题的原因。我认为 monad 一词的不一致(通常是不正确的)使用是我很多困惑的根源,也可能是其他人的困惑。
  • @MauricioScheffer:如果你说“列表会产生一个幺半群”,我可能会问你想到了哪些列表(值)---一些?全部?此外,“产生”是不必要的模糊。
【解决方案2】:

List 是 monad,List a 是类型,[]List a(类型的元素)。

从技术上讲,monad 是一个具有额外结构的 functor;在 Haskell 中,我们只使用从 Haskell 类型到自身的函子。

因此,它特别是一个“函数”,它接受一种类型并返回另一种类型(它有一种* -> *)。

ListState sMaybe 等都是单子。 State 不是 monad,因为它有一种 * -> * -> *

(顺便说一句:为了混淆问题,Monads 只是函子,如果我给自己一个偏序集 A,那么它就形成了一个类别,其中 Hom(a, b) = { 1 element } if a A 形成一个函子,单子是那些满足 x A”。另见closure operators。)

(除了 2:因为你似乎知道一些数学,我鼓励你阅读范畴论。你会看到代数结构可以被看作是由单子产生的。见 this excellent blog entry from the excellent blog by Dan Piponi预告片。)

【讨论】:

  • 有趣。那么State 是一个单子,还是State s 一个单子?
  • @LaurenceGonsalves:State s 是一个单子。 State 有种* -> * -> *
【解决方案3】:

确切地说,monad 是范畴论中的结构。他们没有直接对应的代码。为简单起见,让我们讨论通用函子而不是 monad。在 Haskell 的情况下,大致来说,函子是从一类类型到一类类型的映射,它也将第一类中的函数映射到第二类中的函数。 Functor 实例使您可以访问映射函数,但不直接捕获函子的概念。

但是公平地说,Functor 实例中提到的类型构造函数是实际的函子:

instance Functor Tree

在这种情况下,Tree 是函子。然而,因为Tree 是一个类型构造函数,它不能代表同时生成函子的两个映射函数。映射函数的函数称为fmap。因此,如果你想精确,你必须说元组(Tree, fmap) 是函子,其中fmap 是来自TreeFunctor 实例的特定fmap。再次为方便起见,我们称Tree 是函子,因为对应的fmap 来自其Functor 实例。

请注意,函子总是* -> * 的类型。所以Maybe Int 不是函子——函子是Maybe。人们也经常谈论“国家单子”,这也是不准确的。 State 是一个包含无限多个状态单子的整个家族,正如您在实例中看到的那样:

instance Monad (State s)

对于每个类型s,类型构造函数State s(类型为* -> *)是一个状态单子,是众多单子之一。

【讨论】:

    【解决方案4】:

    那么,你能说“Just 5 is a monad”,还是说“5 is a ring”是错误的?

    你的直觉是完全正确的。 IntRing(或AbelianGroup 或其他),因为MaybeMonad(或Functor 或其他)。值(5Just 5 等)并不重要。

    在代数中,我们说整数的集合形成一个环;在 Haskell 中,我们会(非正式地)说 IntRing 类型类的成员,或者(稍微更正式地)存在 RingInt 实例。您可能会发现 this proposal 有趣和/或有用。无论如何,对单子也是如此。

    我不懂范畴论,但是...

    不管怎样,如果你对抽象代数有所了解,那你就是个天才。

    【讨论】:

      【解决方案5】:

      我会说“只有 5 是 Monad 实例的类型”,就像我会说“5 是具有类型 (Integer) 是环的数字”。

      我使用术语实例是因为在 Haskell 中你是如何声明一个类型类的实现的,而 Monad 就是其中之一。

      【讨论】:

      • 好的,听起来您同意“monad”是适用于类型的术语,而不适用于该类型的单个值。我避免在我的问题中使用术语“实例”,因为虽然 Haskell 使用它来指代类型(例如:类型 Maybe 是 Monad 类型类的一个实例),但许多(大多数?)程序员使用“实例”来指代类型。我认为这实际上可能是许多谈论 monad 的事情对这个问题感到困惑的部分原因。
      • 是的,Monad 绝对在类型上,因为绑定运算符与类型一起工作,您提供的值只是该 monad 类型的东西。这样编译器就可以确保特定的 Monad 实例方法可以安全地应用于该值。 BTW,如果您对答案感到满意,您能接受吗?谢谢!
      • 直到最后一条评论我都和你在一起。 “......绑定运算符使用类型,您提供的值只是该 monad 类型的东西。这样编译器可以确保特定的 Monad 实例方法可以安全地应用于该值。”都与术语无关。以“收藏”和“列表”为例。在某些语言中,它们都是类型,而 List 是 Collection 的子类型。因此,您可以在 Collection 上执行的任何操作都可以在 List 上执行(例如:找出它的大小),这都是静态类型安全的。但是,List 类型的值是一个 Collection。
      • 真的吗?我无法理解:请在 Haskell 中发布一个继承示例,我认为这就是您所说的......
      • 我不是专门谈论 Haskell。我说的是通用术语。 (我确实在这个问题上有一段时间的 Haskell 标签,但实际上是在你发表评论之后。)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多