【问题标题】:Monad in non-programming terms [duplicate]非编程术语中的 Monad [重复]
【发布时间】:2011-03-16 18:13:46
【问题描述】:

可能重复:
What is a monad?

你会如何用非编程术语来描述一个 monad?是否有一些编程之外的概念/事物(在所有编程之外,而不仅仅是 FP)可以说在很大程度上表现或类似于 monad?

【问题讨论】:

  • 我想我听说 monads 是关于在 endospacesuit 类别中涉及超载墨西哥卷饼操作员的事情。我不知道,听起来很复杂。
  • Ehrm,“monad”不是已经不是编程术语了吗?
  • 解释上面第一个笑话评论中的一些参考:the spacesuit tutorialburrito analogyoverloading semicolon 想法、explanation involving categories,以及,嗯,单子“听起来”的一般模因相当复杂”。
  • @fig-gnuton:好的,那么这是一个严肃的回复:再次阅读 ShreevatsaR 的回答。阅读他链接的内容。这样做直到你明白为什么像你要求的类比没有帮助。如果您想认真对待某个问题,当您不喜欢得到的正确答案时,不要抱怨。你真的认真对待学习吗?

标签: haskell functional-programming monads


【解决方案1】:

是的,在编程之外有几件事可以说是像 monad。不,它们都不会帮助你理解单子。请阅读Abstraction, intuition, and the “monad tutorial fallacy”

Joe Haskeller 正在尝试学习 monad。在努力理解了一周之后,看例子,写代码,读别人写的东西,他终于“啊哈!”瞬间:一切都变得清晰起来,Joe 了解 Monads!当然,真正发生的事情是乔的大脑已经将所有细节组合成一个更高层次的抽象,乔可以用这个比喻来直观地掌握单子;让我们假设乔的比喻是单子就像墨西哥卷饼。在这里,乔严重误解了自己的思维过程:“当然!”乔想。 “现在一切都那么简单。理解单子的关键是它们就像墨西哥卷饼。要是我早有这个想法就好了!”当然,问题在于,如果乔之前就想到了这一点,那就无济于事了:在细节上苦苦挣扎的那一周是形成乔的墨西哥卷饼直觉的必要且不可或缺的一部分,而不是他未能击中的可悲后果早点想到。

但是现在乔开始编写一个名为“Monads are Burritos”的 monad 教程,这是出于善意但错误的假设,即如果其他人阅读了他的神奇洞察力,那么学习 monad 对他们来说将是一件轻而易举的事。 “单子很容易,”乔写道。 “把它们想象成墨西哥卷饼。” Joe 隐藏了关于类型等的所有实际细节,因为它们很可怕,如果人们能避免所有那些困难和令人困惑的东西,他们会学得更好。当然,情况恰恰相反,Joe 所做的只是让人们更难了解 monad,因为现在他们不得不花一周时间认为 monad 是墨西哥卷饼并变得一头雾水,然后一星期试图忘记关于墨西哥卷饼的类比,在他们真正开始学习单子之前。

正如我很久以前在another answer 中所说的,sigfpe 的文章You Could Have Invented Monads! (And Maybe You Already Have.) 以及 Philip Wadler 的原始论文Monads for functional programming 都是很好的介绍(不是类比而是很多例子),但除此之外你只是继续编码,最终一切都会变得微不足道。

[不是一个真正的答案:单子存在于所有编程之外的地方,当然,在数学中。正如this hilarious post 指出的那样,“单子是内函子类别中的幺半群,有什么问题?” :-)]


编辑:提问者似乎将这个答案解释为居高临下,说“Monads 是如此复杂以至于无法类比”。事实上,没有任何意图,它是 often appear condescending 的 monad 类比。也许我应该将我的观点重申为“您不必了解 monads”。你使用特定的 monad,因为它们很有用——当你需要 Maybe 类型时你使用 Maybe monad,当你需要做 IO 时你使用 IO monad,类似other examplesapparently in C#,你使用 Nullable 模式、LINQ 和查询理解等。现在,对于理解或使用特定的 monad,没有必要了解所有这些结构背后有一个单一的通用抽象,我们称之为 monad。在您看到多个示例并识别出一种模式之后,它可以作为事后的想法出现:学习从具体到抽象。通过诉诸抽象本身的类比来直接解释抽象通常不会帮助学习者掌握它的抽象。

【讨论】:

  • 这是一个不幸的情况。我想知道this guy 是否找到了他要求的 monad 教程?
  • “跛脚”?不。任何抽象概念都可以通过查看各种特殊情况(示例)和概括来学习,但很少通过类比(通常是不完美的,充其量可以使它不那么令人生畏,无助于理解)。 你理解了 monad 是什么之后,你将能够想出大量的类比——而且这个练习甚至可能对你有所帮助——但是没有证据表明任何一个类比的 monad 教程曾经帮助任何人首先了解他们。 :-)
  • (我试图提取足以理解这一点的最小量。)单子没有什么特别之处。每个抽象都是如此。单子实际上并没有那么复杂。只需看一下示例,了解您关心的 monad,超越可怕的名称并开始编码,总有一天,总的想法会点击。请参阅timeline of monad tutorials,了解已编写的无数单子教程中的一小部分,以及各种类比。他们帮不上什么忙!
  • @fig-gnuton:或者也许是那些 从经验中讲 专注于类比让真正理解变得更难的Haskellers。由于您的问题被误导了,因此对未回答的问题进行了投票。为什么不再读一遍this answer,因为你可能不会得到比那个更好的解释,而且肯定不是来自“现实世界”的类比。
  • Ralph B. Boas 的相关引述,[我们可以让数学变得可理解吗?](jstor.org/stable/2321471):“假设你想教‘猫’这个概念一个很小的孩子。你是否解释说猫是一种相对较小的主要食肉哺乳动物,具有可伸缩的爪子、独特的声音输出等?我敢打赌,你可能会向孩子展示很多不同的猫说“小猫” ' 每次直到它得到想法。更一般地说,概括最好通过从经验中抽象出来。”
【解决方案2】:

这是我目前的尝试:

Monad 是 桶旅

  1. 每个操作都是一个人排队;即,操作发生的顺序很明确。
  2. 每个人将一个桶作为输入,从中取出东西,然后将新的东西放入桶中。桶又会被传递给旅中的下一个人(通过绑定或>>= 操作)。
  3. return 操作只是将东西放入桶中的操作。
  4. 在顺序 (>>) 操作的情况下,桶的内容在传递给下一个人之前被转储。下一个人不在乎桶里有什么,他们只是在等待接收。
  5. 对于() 上的monad,一张票在桶内传递。它被称为“单元”,它只是一张白纸。
  6. 在 IO monad 的情况下,每个人都会大声说出一些非常深刻或非常愚蠢的话——但他们只能在拿着桶的时候说话。

希望这会有所帮助。 :-)


编辑:感谢您的支持,但遗憾的是,Monad 教程的诅咒又来了。我所描述的只是带有容器的函数应用程序,而不是单子!但我不是虚无主义者——我相信 Monad Tutorial 的诅咒可以被打破!所以这里有一张更,嗯,复杂的图片,我认为它更好地描述了它。您决定是否值得带给您的朋友。

Monad 是一个项目经理组成的团队。项目经理站在除了该旅的第一名成员之外的所有人后面。水桶大队的成员坐在凳子上,前面放着水桶。

第一个人收到一些东西,用它做某事,然后把它放在桶里。然后那个人放手——不给旅里的下一个人,那太容易了! :-) – 但对站在那个人背后的项目经理。

项目经理(她的名字是 bind>>=)拿起存储桶并决定如何处理它。她可能决定把第一个人的东西从桶里拿出来,然后毫不犹豫地把它交给她面前的人(这就是 IO monad)。她可能会选择扔掉水桶并结束大队(即fail)。她可能决定绕过她面前的人,毫不费力地将水桶传给旅中的下一位经理(这就是 Maybe monad 中的 Nothing 发生的情况)。她甚至可能决定把桶里的东西拿出来,一次一块地递给她面前的人! (这就是 List monad。)在序列 (>>) 的情况下,她只是轻拍她面前的人的肩膀,而不是递给他们任何东西。

当下一个人制作了一桶东西时,该人会将其交给下一位项目经理。下一位项目经理再次弄清楚如何处理她给的桶,并将桶中的东西交给她的人。最后,存储桶被返回传递给项目经理链,项目经理可以选择使用存储桶做一些事情(例如 List monad 组装所有结果)。结果,第一个项目经理产生了一桶东西。

do 语法的情况下,每个人实际上都是在之前的所有内容的上下文中现场定义的操作 - 好像项目经理不仅传递存储桶中的内容,还传递该旅的前任成员产生的价值(呃,东西)。在这种情况下,如果您使用绑定和序列而不是使用do 语法来写出计算,则在这种情况下构建上下文会更容易查看——注意每个连续的“语句”都是在该点之前的操作中构造的匿名函数。

() 值、IO monad 和 return 操作仍然如上所述。

“但这太复杂了!为什么人们不能自己卸桶?”我听到你问。好吧,项目经理可以在幕后做大量工作,否则会使该人的工作复杂化。我们正在努力让这些旅团成员变得轻松,所以他们不必做太多事情。例如,在 Maybe monad 的情况下,每个人都不必检查他们被给予的东西的价值,看看他们是否被给予了任何东西——项目经理会为他们处理这些。

“好吧,那么,如果你真的想让每个人的工作更轻松,为什么不一路走下去——让一个人拿东西和交东西,让项目经理担心分桶?”经常这样做,并且它有一个特殊的名称,称为将人(呃,操作)提升到 monad。但是,有时,您需要一个人做一些更复杂的事情,他们希望对生成的存储桶进行一些控制(例如,在Maybe monad 的情况下,他们是否需要返回Nothing),并且这就是 monad 所提供的。

要点是:

  1. 操作按顺序排列。
  2. 每个人都知道如何制作水桶,但不知道如何从水桶中取出东西。
  3. 每个项目经理都知道如何处理存储桶,以及如何从中取出东西,但并不关心其中的内容。

我的睡前教程到此结束。 :-P

【讨论】:

  • 那么,如何使用这个类比更容易描述State monad 的getput 操作?或者,也许是 Cont monad 和 callCC
  • 它没有——get、put 和 callCC 不是与 monad 本身相关的操作。这个类比是为了让 Monad 类完全掌握在自己的手中,并侧重于每个 monad 核心的绑定和排序操作。
  • 只是为了确保您感到恼火:MonadState 有它自己的类比。在这种情况下没有水桶,但有一种状态在水桶大队中无形传递。 Get 是一个复制状态(概念上)并传递状态副本的人。 Put 用他收到的任何东西替换状态并递出一张空纸。其他人都忽略了状态,只处理他们所收到的东西,这是关键部分。 runState 设置整个事物并返回最终状态以及最终值。
  • 干得好。在你理解了 monad 教程之后编写它们似乎是学习经验的一部分,但我仍然认为它们对作者的帮助比对 monads 新手的帮助更大。 :-)
  • 并不是说你的类比有什么问题——它们很好。只是,与往常一样,它们不太可能对尚未掌握这些概念的人有任何好处。
【解决方案3】:

在非编程方面:

如果FG是一对伴随函子,F左伴随G,那么GF 是一个单子。

【讨论】:

  • 您是从维基百科复制the sentence 吗? :-) 实际上,数学中的函数式编程单子apparently correspond to strong monads
  • 这没有帮助;你刚刚从编程转向(可能)数学术语......
  • RCIX:你想要什么条款? Monad 是一个数学概念。
  • 这并没有真正的帮助——几乎所有知道什么是伴随函子的人都知道什么是单子。而且,如前所述,在这种情况下,它是一个需要解释的强 monad。
  • @Mau,函子与编程有什么关系?我应该考虑程序(指令集)执行的操作,还是要执行的文件的文本
【解决方案4】:

是否有一些编程之外的概念/事物(除了所有 编程,而不仅仅是 FP),它可以说是在一个 重要的方式?

是的,事实上有。通过 Curry-Howard 同构的扩展,Monad 与模态逻辑中的“可能性”直接相关。 (见:A Judgmental Reconstruction of Modal Logic.

这是一个相当强的关系,对我来说,逻辑方面与可能性相关的概念比范畴论中与单子相关的概念更直观。我发现向我的学生解释 monad 的最佳方式是利用这种关系,但没有明确显示同构。

基本思想是,没有 monad,所有表达式都存在于同一个世界中,所有计算都在那个世界中完成。但是单子可以有很多世界,计算在它们之间移动。 (例如,每个世界都可能指定某个可变状态的当前值)

在这种观点中,monad p 的意思是“在当前世界可能到达的世界中”。

特别是如果t 是一个类型,那么:

x :: t 表示 t 类型的东西在当前世界中直接可用
y :: p t 表示 t 类型的东西在当前世界可到达的世界中可用

然后,return 允许我们将当前世界用作可到达的世界。

return :: t -> p t

>>= 允许我们利用可到达世界中的某物,然后从该世界到达其他世界。

(>>=) :: p t -> (t -> p s) -> p s

因此,>>= 可用于构建一条从较小路径到其他世界的可到达世界的路径。

世界就像状态一样,这很容易解释。对于像 IO monad 这样的东西,它也很简单:一个世界是由一个程序与外部世界的所有交互来指定的。

对于不终止的世界,两个世界就足够了——一个普通的世界,一个无限远的未来。 (在第二个世界中应用 >>= 是允许的,但你不太可能观察到那个世界中发生的事情。)对于延续单子,当正常使用延续时,世界保持不变,并且当它们使用额外的世界时不是(例如,对于 callcc)。

【讨论】:

  • 哇,这是一个优秀的看待它的方式——它使因果结构更加有形,我认为也可以扩展以清楚地说明为什么Monad可以嵌入流控制但Applicative 不能。事实上,我认为这是我听过的唯一一个不是从函子或程序的操作行为开始的对 monad 的好的描述。我肯定需要阅读那篇论文,谢谢!
  • 谢谢 - 这种观点在 ML 圈子(尤其是 CMU)中很常见,但在 Haskell 中则不然。也许在“Monads”维基百科页面中添加类似上面的内容是合适的?顺便说一句,那篇论文首先是关于制定模态逻辑的——这样做之后,“可能性”和“必要性”对应于一个抽象的单子-单子对。要获得强大的单子(如 Haskell),您需要进行限制,以便所有假设都是必要的。或者,您可以模拟强 monad 无法将线程迁移到远程主机的效果 - 请参阅大部分内容:cs.cmu.edu/~jwmoody/pub.htmlcs.cmu.edu/~tom7/papers
  • 我对 monad 是什么和做什么的内部理解仍在逐渐掌握,不得不说这个描述与我的直觉非常吻合。很好的答案。
【解决方案5】:

来自 Mike Vanier 的 this excellent post

Haskell 中的关键概念之一 这使它有别于其他 编程语言是概念 一个“单子”。人们似乎发现了这个 难学(我也学过), 结果有很多 网络上的 monad 教程,一些 非常好(我特别 像 Jeff 的 All About Monads 纽伯恩)。甚至有人说 编写 monad 教程是一种仪式 新 Haskell 程序员的通道。 然而,许多人的一个大问题 monad教程是他们尝试 解释什么是参考单子 对读者现有的概念 已经明白(我什至见过 这在西蒙的演讲中 佩顿-琼斯,主要作者 GHC 编译器和通用 Haskell 宏 呸)。这是一个错误,我是 会告诉你为什么。

这是很自然的,当你试图解释 什么是东西,用什么来解释 指代他人的事物 已经知道了。这很好用 当新事物在某些方面相似时 对待他人的方式 熟悉。它彻底崩溃 当新事物完全消失时 人的经历 学习它。例如,如果你是 试图向一个人解释什么是火 从未见过火的穴居人, 你打算说什么? “这有点像 空气和水的交叉,但是 热...”不是很有效。同样, 解释原子是什么 量子力学是有问题的, 因为我们知道电子 真的不会绕着 原子核就像围绕恒星的行星, 以及“非本地化”的概念 电子云”并不真正意味着 很多。费曼曾经说过,没有人 真正了解量子力学, 在直观的层面上,这是真的。 但在数学层面上,量子 力学很好理解;我们刚刚 对什么没有很好的直觉 数学真的很重要。

这与 monad 有什么关系?时间 再次,在教程、博客文章中 在 Haskell 邮件列表中,我已经 看到单子在两个之一中解释 所谓直观的方式:monad 是 “有点像一个动作”或“有点像 像一个容器”。怎么会有东西 既是动作又是容器? 这些不是独立的概念吗?是一个 monad 某种奇怪的“活跃 容器”?不,但重点是 声称 monad 是一种 动作或一种容器是 不正确。那么什么是单子呢?

答案是:单子是 纯粹抽象的概念,没有 与任何事物的基本关系 你可能听说过 之前。 monad 的概念来了 根据范畴论,即 最抽象的数学分支 I 了解。事实上,整点 范畴论就是抽象出所有 数学的结构 揭露相似之处和类比 在看似不同的区域之间(对于 例如,代数和 拓扑),从而凝聚 将数学纳入其基础 概念,从而减少冗余。 (我可以继续讨论这个问题 虽然,但我宁愿回到 我正在努力说明这一点。)因为我 猜想大多数程序员 学习 Haskell 不太了解 范畴论,单子不会去 对他们来说意味着什么。那不 意味着他们需要学习所有关于 使用单子的范畴论 Haskell(幸运的是),但确实如此 意味着他们需要舒服 多思考一些事情 比他们可能的抽象方式 习惯了。

请到文章顶部的链接阅读全文。

【讨论】:

【解决方案6】:

在实践中,我使用过的大多数 monad 都表现得像某种隐式上下文。

这就像你和一个朋友试图谈论一个共同的朋友一样。每次你说“鲍勃”时,你们都指的是同一个鲍勃,而且由于鲍勃是你们共同的朋友,这一事实只是隐含地贯穿了你们的谈话。

当然,您可以与您的老板(而不是您的朋友)讨论您恰好名叫 Bob 的跨级别经理(不是您的朋友)。在这里,您可以进行另一次对话,再次带有一些仅在对话上下文中才有意义的隐含含义。你甚至可以说出和朋友说的完全相同的话,但由于上下文不同,它们的含义会有所不同。

在编程中也是如此。 tell 的行为方式取决于您所在的 monad;信息的组合方式 (>>=) 取决于您所在的单子。相同的想法,不同的对话方式。

哎呀,即使是对话规则也可以是一元的。 “不要告诉任何人我告诉过你的”隐藏信息的方式与 runST 防止引用转义 ST monad 的方式相同。显然,对话可以有一层又一层的上下文,就像我们有一堆 monad 转换器一样。

希望对您有所帮助。

【讨论】:

  • 对 - 隐式上下文基本上就是我在回答中所说的“可能到达的世界”。不过有一件事:comonads 还涉及隐式上下文,您的解释似乎适合它们以及 monads(除了提到 >>= 和 runST)。也许更准确地说,它应该更具体地说明上下文的变化是如何发生的。
【解决方案7】:

好吧,这里是a nicely detailed description of monads,这绝对超出了所有编程范围。我知道它不属于编程,因为我是一名程序员,我连它所说的一半都不懂。

YouTube 上还有一系列视频解释了各种单子——这里是 the first in the sequence

不过,我猜这并不是您真正想要的......

【讨论】:

  • 其实范畴论和编程有很大关系。从某种意义上说,宇宙学与天文学有关。
【解决方案8】:

我喜欢将它们视为可以“绑定”的计算的抽象。或者,墨西哥卷饼!

【讨论】:

    【解决方案9】:

    这取决于您与谁交谈。任何解释都必须放在正确的水平上。我对化学工程师的解释不同于我对数学家或财务经理的解释。

    最好的方法是将其与您正在与之交谈的人的专业知识联系起来。作为一个规则排序是一个相当普遍的问题,所以试着找到一些人知道你说“先做X,然后做Y”的地方。然后解释一下普通的编程语言是如何出现这个问题的;如果你对计算机说“做 X,然后做 Y”,它会立即做 X 和 Y,而无需等待进一步的输入,但它不能同时为其他人做 Z;计算机的“然后做”的想法与您的不同。因此,程序员必须以不同于您(专家)解释程序的方式编写程序。这会在您所说的内容与程序所说的内容之间产生差距。跨越这个鸿沟需要时间和金钱。

    Monads 让你把你的“然后做”版本放到电脑里,所以你可以说“做 X 然后做 Y”,程序员可以写“做 {x ; y}”,这意味着什么你的意思是。

    【讨论】:

      【解决方案10】:

      是的,Monads 来自 haskell 之外的一个概念。 Haskell 有许多从范畴论中借用的术语和思想。这是其中之一。所以如果这个不是程序员的人原来是一个研究过范畴论的数学家,就说:“Monad 是内函子范畴中的幺半群。”

      【讨论】:

      • 我对 modad 了解不多,但作为一名对范畴论有一定经验的前数学家,我认为您的答案是这里最好的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-18
      • 2020-02-24
      • 1970-01-01
      • 2011-06-20
      • 2017-07-25
      相关资源
      最近更新 更多