在最近简要回顾了Haskell之后,对于monad本质上是什么,有什么简单、简洁、实用的解释?
我发现,我遇到的大多数解释都很难理解,而且缺乏实际细节。
在最近简要回顾了Haskell之后,对于monad本质上是什么,有什么简单、简洁、实用的解释?
我发现,我遇到的大多数解释都很难理解,而且缺乏实际细节。
当前回答
monad是一个容器,但用于数据。一个特殊的容器。
所有容器都可以有开口、把手和喷口,但这些容器都保证有一定的开口、把手或喷口。
为什么?因为这些有保证的开口、把手和喷口对于以特定、常见的方式拾取和连接容器非常有用。
这使您可以选择不同的容器,而不必对它们了解太多。它还允许不同类型的容器轻松连接在一起。
其他回答
根据我们所谈论的monad,“什么是monad”这个问题是错误的:
对“什么是单单体?”这个问题的简短回答是,它是内函子范畴中的单单体,或者它是一种通用数据类型,配备了满足某些定律的两个运算。这是正确的,但它并没有揭示一个重要的大局。这是因为问题是错误的。在这篇论文中,我们的目标是回答正确的问题,即“当作者谈论单子时,他们真正说的是什么?”
虽然这篇论文没有直接回答什么是单子,但它有助于理解不同背景的人谈论单子时的含义以及原因。
解释monad似乎就像解释控制流语句一样。想象一下,一个非程序员要求你解释它们?
你可以给他们一个涉及理论的解释——布尔逻辑、寄存器值、指针、堆栈和框架。但那太疯狂了。
你可以用语法来解释它们。基本上,C中的所有控制流语句都有大括号,您可以通过它们相对于括号的位置来区分条件和条件代码。这可能更疯狂。
或者,您也可以解释循环、if语句、例程、子例程以及可能的协例程。
Monad可以取代相当多的编程技术。语言中有一种特定的语法支持它们,还有一些关于它们的理论。
它们也是函数式程序员使用命令式代码而不承认它的一种方式,但这并不是他们唯一的用途。
但是,你本可以发明蒙纳斯!
sigfpe说:但所有这些都将单子介绍为需要解释的深奥的东西。但我想说的是,它们一点都不深奥。事实上,面对函数式编程中的各种问题,你会不可避免地被引向某些解决方案,所有这些都是单子的例子。事实上,如果你还没有发明,我希望你现在就发明它们。这是注意到所有这些解决方案实际上都是变相的相同解决方案的一小步。读完这篇文章后,你可能会更好地理解单子上的其他文档,因为你会发现你所看到的一切都是你已经发明的。monads试图解决的许多问题都与副作用有关。因此,我们将从它们开始。(请注意,monad让您做的不仅仅是处理副作用,特别是许多类型的容器对象都可以被视为monad。monad的一些介绍发现,很难协调monad的这两种不同用法,并且只关注其中一种。)在命令式编程语言(如C++)中,函数的行为与数学函数完全不同。例如,假设我们有一个C++函数,它接受一个浮点参数并返回一个浮点结果。从表面上看,它可能有点像一个将实数映射到实数的数学函数,但C++函数可以做的不仅仅是返回一个依赖于其参数的数字。它可以读取和写入全局变量的值,也可以将输出写入屏幕并接收用户的输入。然而,在纯函数语言中,函数只能读取在其参数中提供给它的内容,而它对世界产生影响的唯一方式是通过它返回的值。
在了解这些信息时,对我帮助最大的两件事是:
第8章,“函数解析器”,摘自Graham Hutton的《Haskell编程》一书。实际上,这根本没有提到monad,但如果您能够通读第章并真正理解其中的所有内容,特别是如何评估一系列绑定操作,您将了解monad的内部结构。预计这需要多次尝试。
关于修道院的教程。这提供了几个很好的例子来说明它们的用途,我不得不说,我在Appendex中的类比是为我工作的。
我最喜欢的Monad教程:
http://www.haskell.org/haskellwiki/All_About_Monads
(在谷歌搜索“monad教程”的17万次点击中!)
@斯图:monads的目的是允许您将(通常)顺序语义添加到纯代码中;您甚至可以组合Monad(使用Monad Transformers)并获得更有趣和复杂的组合语义,例如,带有错误处理的解析、共享状态和日志记录。所有这些在纯代码中都是可能的,monad只允许您将其抽象并在模块化库中重用(在编程中总是很好的),并提供方便的语法使其看起来势在必行。
Haskell已经有了运算符重载[1]:它使用类型类的方式与使用Java或C#中的接口的方式非常相似,但Haskell恰好也允许使用非字母数字标记(如+&&和>)作为中缀标识符。如果您的意思是“重载分号”[2],那么在您看来这只是运算符重载。“重载分号”听起来像是黑魔法,自找麻烦(想象一下有进取心的Perl黑客听到了这个想法),但关键是没有monad就没有分号,因为纯函数代码不需要或不允许显式排序。
这一切听起来比实际情况要复杂得多。sigfpe的文章很酷,但使用了Haskell来解释它,这有点无法打破理解Haskell到grok Monads和理解Monads到grok Haskell的鸡和蛋的问题。
[1] 这是与monad不同的问题,但monad使用Haskell的运算符重载特性。
[2] 这也是一个过度简化,因为链接一元操作的运算符是>>=(发音为“bind”),但有语法糖(“do”)允许您使用大括号和分号和/或缩进和换行。