在最近简要回顾了Haskell之后,对于monad本质上是什么,有什么简单、简洁、实用的解释?

我发现,我遇到的大多数解释都很难理解,而且缺乏实际细节。


当前回答

monad是一种将共享共同上下文的计算组合在一起的方法。这就像建立一个管道网络。当构建网络时,没有数据流过它。但是当我用“bind”和“return”将所有位拼接在一起后,我调用类似runMyMonad monad数据的东西,数据流过管道。

其他回答

如果你要求对如此抽象的东西做出简洁、实用的解释,那么你只能希望得到一个抽象的答案:

a -> b

是表示从as到bs的计算的一种方式。您可以将计算链接起来,也可以将它们组合在一起:

(b -> c) -> (a -> b) -> (a -> c)

更复杂的计算需要更复杂的类型,例如:

a -> f b

是从as到bs到fs的计算类型。您还可以编写它们:

(b -> f c) -> (a -> f b) -> (a -> f c)

事实证明,这种模式无处不在,并且与上面的第一个组合具有相同的财产(结合性、右-和左-同一性)。

人们必须给这个模式起一个名字,但如果知道第一个组合被正式描述为半群体,这会有帮助吗?

“单子和圆括号一样有趣和重要”(奥列格·基斯廖夫)

另一种尝试是解释monad,只使用Python列表和map函数。我完全接受这不是一个完整的解释,但我希望它能触及核心概念。

我从Monads上的funfunfunction视频和Learn You A Haskell章节“为了几个Monads更多”中得到了这一点的基础。我强烈推荐观看funfunfunction视频。

最简单的是,Monad是具有map和flatMap函数(在Haskell中绑定)的对象。有一些额外的必需财产,但这些是核心属性。

flatMap“展平”map的输出,对于列表,这只是连接列表的值,例如。

concat([[1], [4], [9]]) = [1, 4, 9]

因此,在Python中,我们基本上可以通过以下两个函数实现Monad:

def flatMap(func, lst):
    return concat(map(func, lst))

def concat(lst):
    return sum(lst, [])

func是任何接受值并返回列表的函数。

lambda x: [x*x]

解释

为了清楚起见,我通过一个简单的函数在Python中创建了concat函数,该函数将列表相加,即[]+[1]+[4]+[9]=[1,4,9](Haskell有一个原生的concat方法)。

我假设你知道地图功能是什么,例如:

>>> list(map(lambda x: [x*x], [1,2,3]))
[[1], [4], [9]]

展平是Monad的关键概念,对于每个作为Monad的对象,这种展平允许您获得Monad中包裹的值。

现在我们可以呼叫:

>>> flatMap(lambda x: [x*x], [1,2,3])
[1, 4, 9]

这个lambda取一个值x并将其放入一个列表中。monad适用于从值到monad类型的任何函数,所以在本例中是列表。

这是你的monad定义。

我认为为什么它们有用的问题已经在其他问题中得到了回答。

更多说明

其他不是列表的例子有JavaScript Promise,它有then方法,JavaScript Streams有flatMap方法。

因此Promise和Streams使用了一个稍微不同的函数,它将Stream或Promise展平,并从内部返回值。

Haskell列表monad具有以下定义:

instance Monad [] where  
    return x = [x]  
    xs >>= f = concat (map f xs)  
    fail _ = [] 

即有三个函数return(不要与大多数其他语言中的return混淆)、>>=(flatMap)和fail。

希望您能看到以下两者之间的相似之处:

xs >>= f = concat (map f xs)

and:

def flatMap(f, xs):
    return concat(map(f, xs))

如果我理解正确的话,IEnumerable是从monad派生出来的。我想知道,对于我们这些来自C#世界的人来说,这可能是一个有趣的视角吗?

值得一提的是,这里有一些帮助我的教程链接(不,我还不知道单子是什么)。

http://osteele.com/archives/2007/12/overloading-semicolonhttp://spbhug.folding-maps.org/wiki/MonadsEnhttp://www.loria.fr/~kow/monads/

Monad用于控制流,就像抽象数据类型用于数据一样。

换句话说,许多开发人员对集合、列表、字典(或哈希、或地图)和树的概念很熟悉。在这些数据类型中有许多特殊情况(例如InsertionOrderPreservingIdentityHashMap)。

然而,当面对程序“流”时,许多开发人员还没有接触到比if、switch/case、do、while、goto(grr)和(可能)闭包更多的构造。

因此,monad只是一个控制流构造。替代monad的更好短语是“控制类型”。

因此,monad具有用于控制逻辑、语句或函数的槽——数据结构中的等价物是,某些数据结构允许您添加数据,并删除数据。

例如,“if”monad:

if( clause ) then block

最简单的是有两个槽:一个子句和一个块。if monad通常用于评估子句的结果,如果不是false,则评估块。许多开发人员在学习“如果”时并没有接触到monad,而且编写有效的逻辑并不需要理解monad。

monad可能会变得更复杂,就像数据结构可能变得更复杂一样,但monad有很多大类可能具有相似的语义,但实现和语法不同。

当然,数据结构可以在单子上迭代或遍历,也可以以同样的方式进行评估。

编译器可能支持也可能不支持用户定义的monad。哈斯克尔当然知道。Ioke有一些类似的功能,尽管语言中没有使用monad一词。

http://code.google.com/p/monad-tutorial/正是为了解决这个问题而进行的工作。