在最近简要回顾了Haskell之后,对于monad本质上是什么,有什么简单、简洁、实用的解释?
我发现,我遇到的大多数解释都很难理解,而且缺乏实际细节。
在最近简要回顾了Haskell之后,对于monad本质上是什么,有什么简单、简洁、实用的解释?
我发现,我遇到的大多数解释都很难理解,而且缺乏实际细节。
当前回答
(另请参见“什么是monad?”中的答案)
蒙纳斯的一个很好的动机是西格菲(丹·皮波尼)的《你本可以发明蒙纳斯!(也许你已经有了)。还有很多其他monad教程,其中许多都试图使用各种类比以“简单的术语”来解释monad:这就是monad教程谬论;避开它们。
正如MacIver博士在《告诉我们为什么你的语言很糟糕》中所说:所以,我讨厌Haskell的事情:让我们从显而易见的开始。Monad教程。不,不是单子。特别是教程。他们没完没了,夸夸其谈,亲爱的上帝,他们太乏味了。此外,我从未见过任何令人信服的证据表明它们确实有帮助。阅读类定义,编写一些代码,忘掉这个可怕的名字。
你说你懂“也许莫纳德”吗?很好,你在路上了。只要开始使用其他monad,迟早你会了解monad的一般含义。
(如果你以数学为导向,你可能想忽略几十个教程,学习定义,或遵循类别理论的讲座:)定义的主要部分是Monad M包含一个“类型构造器”,为每个现有类型“T”定义一个新类型“M T”,以及在“常规”类型和“M”类型之间来回移动的一些方式。]
同样,令人惊讶的是,对monad最好的介绍之一实际上是介绍monad的早期学术论文之一,Philip Wadler的Monad for functional programming。它实际上有一些实用的、非平凡的激励性例子,与许多人工教程不同。
其他回答
如果我理解正确的话,IEnumerable是从monad派生出来的。我想知道,对于我们这些来自C#世界的人来说,这可能是一个有趣的视角吗?
值得一提的是,这里有一些帮助我的教程链接(不,我还不知道单子是什么)。
http://osteele.com/archives/2007/12/overloading-semicolonhttp://spbhug.folding-maps.org/wiki/MonadsEnhttp://www.loria.fr/~kow/monads/
monad是一个容器,但用于数据。一个特殊的容器。
所有容器都可以有开口、把手和喷口,但这些容器都保证有一定的开口、把手或喷口。
为什么?因为这些有保证的开口、把手和喷口对于以特定、常见的方式拾取和连接容器非常有用。
这使您可以选择不同的容器,而不必对它们了解太多。它还允许不同类型的容器轻松连接在一起。
Monoid似乎可以确保在Monoid和受支持的类型上定义的所有操作始终返回Monoid内部的受支持类型。任何数字+任何数字=一个数字,没有错误。
而除法接受两个分数,并返回一个分数,该分数在haskell somewhy中将除以零定义为无穷大(恰好是分数somewhy)。。。
在任何情况下,Monads似乎只是一种确保您的操作链以可预测的方式运行的方法,而一个声称为Num->Num的函数,由另一个用x调用的Num->Num的函数组成,并不意味着发射导弹。
另一方面,如果我们有一个功能可以发射导弹,我们可以将它与其他功能组合起来,也可以发射导弹。
在Haskell中,main的类型是IO()或IO[()],这种区分很奇怪,我不会讨论它,但我认为会发生以下情况:
如果我有main,我希望它做一系列动作,我运行程序的原因是产生一个效果——通常是通过IO。因此,我可以将IO操作串联在一起,以便——做IO,而不是其他。
如果我尝试做一些不“返回IO”的事情,程序会抱怨链不流动,或者基本上“这与我们正在尝试做的事情有什么关系——IO动作”,这似乎迫使程序员保持思路,不偏离并思考发射导弹,同时创建排序算法——不流动。
基本上,Monads似乎是编译器的一个提示,“嘿,你知道这个函数在这里返回一个数字,它实际上并不总是有效的,它有时会产生一个number,有时什么都没有,请记住这一点”。知道了这一点,如果你试图断言一个单元动作,单元动作可能会作为一个编译时异常,说“嘿,这实际上不是一个数字,这可能是一个数字。但你不能假设这一点。做一些事情以确保流是可接受的。”这在一定程度上防止了不可预测的程序行为。
似乎monad不是关于纯粹性,也不是关于控制,而是关于维护一个类别的身份,在这个类别上,所有行为都是可预测和定义的,或者不编译。当你被要求做某事时,你不能什么都不做,如果你被要求什么都不干(可见),你也不能做。
我能想到的Monads的最大原因是——看看程序/OOP代码,你会发现你不知道程序从哪里开始,也不知道程序的结束,你看到的只是大量的跳跃和大量的数学、魔法和导弹。您将无法维护它,如果可以的话,您将花费大量的时间来思考整个程序,然后才能理解其中的任何部分,因为在这种情况下,模块化是基于代码的相互依赖的“部分”,其中代码被优化为尽可能相关,以保证效率/相互关系。单子是非常具体的,并且通过定义得到了很好的定义,并确保程序流程可以进行分析,并隔离难以分析的部分——因为它们本身就是单子。monad似乎是一个“可理解的单元,它在完全理解时是可预测的”——如果你理解“可能”monad,那么它除了“可能”之外就没有可能做任何事情,这看起来微不足道,但在大多数非monad代码中,一个简单的函数“helloworld”可以发射导弹,什么都不做,或者摧毁宇宙,甚至扭曲时间——我们不知道也不能保证它是什么样子。一个单子保证它就是什么样子。这是非常强大的。
“现实世界”中的所有事物似乎都是单子,因为它受到防止混淆的明确可观察规律的约束。这并不意味着我们必须模仿这个对象的所有操作来创建类,相反,我们可以简单地说“一个正方形就是一个正方形”,只不过是一个正方形,甚至不是矩形或圆形,和“一个正方形的面积是它现有维度的长度乘以它自身的面积。无论你有什么正方形,如果它是2D空间中的正方形,它的面积绝对不能是任何东西,只有它的长度平方,这几乎是微不足道的。这是非常强大的,因为我们不需要断言我们的世界是这样的,我们只需要使用现实的含义来预测它。”防止我们的节目偏离轨道。
我几乎可以肯定是错的,但我认为这可以帮助一些人,所以希望它能帮助一些人。
根据我们所谈论的monad,“什么是monad”这个问题是错误的:
对“什么是单单体?”这个问题的简短回答是,它是内函子范畴中的单单体,或者它是一种通用数据类型,配备了满足某些定律的两个运算。这是正确的,但它并没有揭示一个重要的大局。这是因为问题是错误的。在这篇论文中,我们的目标是回答正确的问题,即“当作者谈论单子时,他们真正说的是什么?”
虽然这篇论文没有直接回答什么是单子,但它有助于理解不同背景的人谈论单子时的含义以及原因。
公主对F#计算表达式的解释帮助了我,尽管我仍然不能说我真的理解了。
编辑:这个系列-用javascript解释monad-对我来说是一个“打破平衡”的系列。
http://blog.jcoglan.com/2011/03/05/translation-from-haskell-to-javascript-of-selected-portions-of-the-best-introduction-to-monads-ive-ever-read/http://blog.jcoglan.com/2011/03/06/monad-syntax-for-javascript/http://blog.jcoglan.com/2011/03/11/promises-are-the-monad-of-asynchronous-programming/
我认为理解单子是一件让你毛骨悚然的事。从这个意义上说,尽可能多地阅读“教程”是一个好主意,但通常奇怪的东西(不熟悉的语言或语法)会让你的大脑无法专注于基本内容。
有些事情我很难理解:
基于规则的解释对我来说从未奏效,因为大多数实际示例实际上需要的不仅仅是返回/绑定。此外,称之为规则也无济于事。这更像是“有些东西有共同点,我们把它们称为‘单子’,把共同点称为‘规则’”。Return(a->M<a>)和Bind(M<a>->(a->M<b>)->M<b>)很好,但我永远无法理解Bind如何从M<a>中提取a,以便将其传递给a->M<b>。我不认为我在任何地方读过(也许这对其他人来说都很明显),Return(M<a>->a)的反面必须存在于monad内部,它只是不需要暴露。