在最近简要回顾了Haskell之后,对于monad本质上是什么,有什么简单、简洁、实用的解释?
我发现,我遇到的大多数解释都很难理解,而且缺乏实际细节。
在最近简要回顾了Haskell之后,对于monad本质上是什么,有什么简单、简洁、实用的解释?
我发现,我遇到的大多数解释都很难理解,而且缺乏实际细节。
当前回答
除了上面出色的答案之外,让我为您提供以下文章的链接(由Patrick Thomson撰写),该文章通过将概念与JavaScript库jQuery(及其使用“方法链接”来操作DOM的方式)相关联来解释monads:jQuery是Monad
jQuery文档本身并没有提到术语“monad”,而是谈到了可能更熟悉的“构建器模式”。这并不能改变一个事实,那就是你有一个合适的monad,也许你甚至没有意识到它。
其他回答
monad是一个容器,但用于数据。一个特殊的容器。
所有容器都可以有开口、把手和喷口,但这些容器都保证有一定的开口、把手或喷口。
为什么?因为这些有保证的开口、把手和喷口对于以特定、常见的方式拾取和连接容器非常有用。
这使您可以选择不同的容器,而不必对它们了解太多。它还允许不同类型的容器轻松连接在一起。
如果我理解正确的话,IEnumerable是从monad派生出来的。我想知道,对于我们这些来自C#世界的人来说,这可能是一个有趣的视角吗?
值得一提的是,这里有一些帮助我的教程链接(不,我还不知道单子是什么)。
http://osteele.com/archives/2007/12/overloading-semicolonhttp://spbhug.folding-maps.org/wiki/MonadsEnhttp://www.loria.fr/~kow/monads/
但是,你本可以发明蒙纳斯!
sigfpe说:但所有这些都将单子介绍为需要解释的深奥的东西。但我想说的是,它们一点都不深奥。事实上,面对函数式编程中的各种问题,你会不可避免地被引向某些解决方案,所有这些都是单子的例子。事实上,如果你还没有发明,我希望你现在就发明它们。这是注意到所有这些解决方案实际上都是变相的相同解决方案的一小步。读完这篇文章后,你可能会更好地理解单子上的其他文档,因为你会发现你所看到的一切都是你已经发明的。monads试图解决的许多问题都与副作用有关。因此,我们将从它们开始。(请注意,monad让您做的不仅仅是处理副作用,特别是许多类型的容器对象都可以被视为monad。monad的一些介绍发现,很难协调monad的这两种不同用法,并且只关注其中一种。)在命令式编程语言(如C++)中,函数的行为与数学函数完全不同。例如,假设我们有一个C++函数,它接受一个浮点参数并返回一个浮点结果。从表面上看,它可能有点像一个将实数映射到实数的数学函数,但C++函数可以做的不仅仅是返回一个依赖于其参数的数字。它可以读取和写入全局变量的值,也可以将输出写入屏幕并接收用户的输入。然而,在纯函数语言中,函数只能读取在其参数中提供给它的内容,而它对世界产生影响的唯一方式是通过它返回的值。
我也在努力理解单子。这是我的版本:
Monad是关于对重复的事物进行抽象的。首先,monad本身是一个类型化接口(像抽象泛型类),它有两个函数:bind和return,它们定义了签名。然后,我们可以基于抽象的monad创建具体的monad,当然还有绑定和返回的具体实现。此外,绑定和返回必须满足几个不变量,以便可以组合/链接具体的单体。
当我们有接口、类型、类和其他工具来创建抽象时,为什么要创建monad概念?因为monad提供了更多:它们以一种能够在没有任何样板的情况下合成数据的方式强制重新思考问题。
实际上,monad基本上允许回调嵌套(具有相互递归的线程状态(请忽略连字符))(以可组合(或可分解)的方式)(具有类型安全性(有时(取决于语言))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
例如,这不是单子:
//JavaScript is 'Practical'
var getAllThree =
bind(getFirst, function(first){
return bind(getSecond,function(second){
return bind(getThird, function(third){
var fancyResult = // And now make do fancy
// with first, second,
// and third
return RETURN(fancyResult);
});});});
但是monad启用了这样的代码。monad实际上是一组类型:{bind,RETURN,也许其他我不认识的人…}。这本质上是无关紧要的,实际上是不切实际的。
所以现在我可以使用它:
var fancyResultReferenceOutsideOfMonad =
getAllThree(someKindOfInputAcceptableToOurGetFunctionsButProbablyAString);
//Ignore this please, throwing away types, yay JavaScript:
// RETURN = K
// bind = \getterFn,cb ->
// \in -> let(result,newState) = getterFn(in) in cb(result)(newState)
或将其分解:
var getFirstTwo =
bind(getFirst, function(first){
return bind(getSecond,function(second){
var fancyResult2 = // And now make do fancy
// with first and second
return RETURN(fancyResult2);
});})
, getAllThree =
bind(getFirstTwo, function(fancyResult2){
return bind(getThird, function(third){
var fancyResult3 = // And now make do fancy
// with fancyResult2,
// and third
return RETURN(fancyResult3);
});});
或者忽略某些结果:
var getFirstTwo =
bind(getFirst, function(first){
return bind(getSecond,function(second){
var fancyResult2 = // And now make do fancy
// with first and second
return RETURN(fancyResult2);
});})
, getAllThree =
bind(getFirstTwo, function(____dontCare____NotGonnaUse____){
return bind(getThird, function(three){
var fancyResult3 = // And now make do fancy
// with `three` only!
return RETURN(fancyResult3);
});});
或者从以下内容简化一个小案例:
var getFirstTwo =
bind(getFirst, function(first){
return bind(getSecond,function(second){
var fancyResult2 = // And now make do fancy
// with first and second
return RETURN(fancyResult2);
});})
, getAllThree =
bind(getFirstTwo, function(_){
return bind(getThird, function(three){
return RETURN(three);
});});
收件人(使用“正确身份”):
var getFirstTwo =
bind(getFirst, function(first){
return bind(getSecond,function(second){
var fancyResult2 = // And now make do fancy
// with first and second
return RETURN(fancyResult2);
});})
, getAllThree =
bind(getFirstTwo, function(_){
return getThird;
});
或者把它们挤在一起:
var getAllThree =
bind(getFirst, function(first_dontCareNow){
return bind(getSecond,function(second_dontCareNow){
return getThird;
});});
这些能力的实用性并没有真正显现出来,或者变得清晰,直到你试图解决真正的棘手问题例如解析或模块/ajax/资源加载。
你能想象成千上万行indexOf/subString逻辑吗?如果频繁的解析步骤包含在小函数中呢?像字符、空格、大写字符或数字这样的函数?如果这些函数在回调中给出了结果,而不必与Regex集团和争论发生冲突?如果它们的组成/分解被很好地理解了呢?这样你就可以从下往上构建大型解析器了吗?
因此,管理嵌套回调范围的能力非常实用,尤其是在使用monadic解析器组合器库时。(也就是说,根据我的经验)
不要挂断电话:-分类理论-可能是月-莫纳德定律-哈斯克尔- !!!!