Help a C# developer understand: What is a monad?
最近有很多关于单子的讨论。我读过几篇文章/博客文章,但我无法用它们的例子来充分理解这个概念。原因是monads是一个功能语言概念,因此这些例子是用我没有使用过的语言(因为我没有深入使用功能语言)。我对句法的掌握不够深入,无法完全理解文章的内容…但我可以看出这里有一些值得理解的东西。
但是,我非常了解C,包括lambda表达式和其他功能特性。我知道C只有功能特性的一个子集,所以也许Monad不能用C表示。
然而,确实有可能传达这个概念吗?至少我希望如此。也许你可以提出一个C示例作为基础,然后描述C开发人员希望从那里做些什么,但是不能,因为语言缺乏功能性编程特性。这将是非常棒的,因为它将传达Monads的意图和好处。所以我的问题是:你能给C 3开发者最好的解释是什么?
谢谢!
(编辑:顺便说一句,我知道已经有至少3个"什么是单子"的问题了。但是,我也面临同样的问题…因此,这个问题是IMO所需要的,因为C-开发人员的重点。谢谢。
整天编程的大部分工作是将一些函数组合在一起,从中构建更大的函数。通常,您不仅在工具箱中有函数,而且还有其他一些东西,比如运算符、变量赋值等,但是通常,您的程序将许多"计算"组合在一起,以进行更大的计算,这些计算将进一步组合在一起。
Monad是一种"结合计算"的方法。
通常,将两个计算组合在一起的最基本的"运算符"是
1 | a; b |
当你这样说的时候,你的意思是"先做
在面向对象语言中,另一个可以被视为monad的东西是
1 | a.b().c().d() |
另一个相当常见的monad没有特殊的语法,它是这样的模式:
2返回值-1表示失败,但没有真正的方法来抽象出这种错误检查,即使您有许多API调用需要以这种方式组合。这基本上只是另一个monad,它按照规则"如果左边的函数返回-1,自己返回-1,否则调用右边的函数"组合函数调用。如果我们有一个操作员
1 | socket.bind(...) >>= socket.connect(...) >>= socket.send(...) |
它将使事物更具可读性,并有助于抽象出我们组合函数的特殊方式,这样我们就不需要一次又一次地重复自己。
还有很多方法可以组合函数/计算,这些函数/计算作为一个通用模式很有用,并且可以在monad中进行抽象,使monad的用户能够编写更简洁和清晰的代码,因为所有使用的函数的簿记和管理都是在monad中完成的。
例如,上面的
1 |
形式定义要复杂一些,因为您必须担心如何获得一个函数的结果作为下一个函数的输入,如果该函数需要该输入,并且因为您希望确保组合的函数符合您尝试在Monad中组合它们的方式。但基本的概念是,将不同的功能组合在一起的方式形式化。
我发表这个问题已经一年了。张贴后,我深入研究了哈斯克尔几个月。我非常喜欢它,但我把它放在一边,就像我准备钻研单子一样。我回到工作中,专注于我的项目所需的技术。
昨晚,我来重新阅读这些回复。最重要的是,我重新阅读了上面提到的布莱恩·贝克曼视频的文本评论中的具体C示例。它是如此的清晰和启发,我决定直接张贴在这里。
因为这个评论,我不仅觉得我完全理解Monads是什么……我意识到我实际上用C写了一些Monads……或者至少写得很近,并且努力解决同样的问题。
所以,这里是评论——这都是Sylvan在这里评论的直接引述:
0monad本质上是延迟处理。如果你试图用一种不允许有副作用的语言编写代码(例如I/O),并且只允许纯计算,那么一个回避就是说,"好吧,我知道你不会为我做副作用,但是你能计算出如果你这样做会发生什么吗?"
有点作弊。
现在,这个解释将帮助你理解蒙纳兹的大局意图,但魔鬼在细节中。你到底是如何计算后果的?有时候,它不漂亮。
对于那些习惯于命令式编程的人来说,最好的方法是说它把你放在一个DSL中,在这个DSL中,语法上类似于你在monad之外所使用的操作被用来构建一个函数,如果你能(例如)写一个输出文件,它将做你想做的事情。几乎(但不是真的),就好像你在一个字符串中构建代码,以便以后被eval'd。
我相信其他用户会深入发布,但我发现这段视频在某种程度上有帮助,但我会说,我对这个概念仍然不够流利,这样我就可以(或应该)开始用monads直观地解决问题。
看我对"什么是单子?"
它以一个激励性的例子开始,通过这个例子工作,派生出一个monad的例子,并正式定义"monad"。
它假定不了解函数编程,并且使用具有最简单表达式的
这个C程序是伪代码monad的一个实现。(参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | using System.IO; using System; class Program { public class M<A> { public A val; public string messages; } public static M feed<A, B>(Func<A, M> f, M<A> x) { M m = f(x.val); m.messages = x.messages + m.messages; return m; } public static M<A> wrap<A>(A x) { M<A> m = new M<A>(); m.val = x; m.messages =""; return m; } public class T {}; public class U {}; public class V {}; public static M<U> g(V x) { M<U> m = new M<U>(); m.messages ="called g. "; return m; } public static M<T> f(U x) { M<T> m = new M<T>(); m.messages ="called f. "; return m; } static void Main() { V x = new V(); M<T> m = feed<U, T>(f, feed(g, wrap<V>(x))); Console.Write(m.messages); } } |
您可以将monad看作类必须实现的C