- 浏览: 3053132 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
上周在JavaEye问答看到求一个逻辑运算结果,其中De Morgan定律的应用如night_stalker老兄所说,并不困难。不过就这么应用定律来推算或许不直观,所以当时我就想换个角度,写段C#代码来穷举验证问题中的表达式在应用De Morgan定律前后的真假值是否总是相同。
通过LINQ,代码很简洁:
这段代码看起来应该算是比较直观的。不过……似乎又不太直观?
对许多人来说,或许显式用循环会直观得多:
但这代码好丑啊 =v=
好吧我作 弊了。就以上两个版本的代码来比较,它们实际的执行过程是不同的;LINQ的版本是会把所有可能性都算出来之后再看是否Contains(),因为Contains是一个eager operator,不像Select、Where那些是lazy的;循环版是遇到不相等的状况就直接退出循环了。不过反正两个版本算出来的结果都一样,用来对比也不算过分。
其实C#的foreach循环已经掩盖了许多细节,不需要显式用下标或者IEnumerator来遍历容器。不过我还是不喜欢在这种场景用显式的循环,主要是因为循环嵌套起来非常难看,搞不好就要超过屏幕的右边了。
之前说LINQ的版本看起来简洁,但未必很直观,是因为:多个from子句连在一起对应的函数是SelectMany,对IEnumerable<T>/IQueryable<T>而言这个LINQ运算符背后的概念则是list monad中的bind函数;其中的机理还是需要读些资料才能理解的。一看到monad这词很多人就要开始晕了吧? =w=
本来是想list monad在C#通过LINQ来使用可以这么简洁,那要是能在Ruby里也这样用就好了。但如标题所说,语言没有提供monad语法的时候,这玩儿写起来也不优雅。其实更关键的问题或许是没有typeclass的条件下monad无法提供统一的接口来提高抽象层次?不过我只想关心语法,也就是“看起来如何”的问题。
例如说,用Ruby来实现一个maybe monad:
定义了Maybe类之后,可以这样用:
看起来还不错,方法调用没有嵌套,都是串在一起的。
但这只不过是因为这一连串计算是从单一的来源得到数据的:那个“1”。假如要把一个“1”和一个“2”都用Maybe包装起来,然后要得到它们的和,那就变成:
于是bind的调用就嵌套起来了,郁闷 T T
我一时觉得纳闷,明明记得在Haskell里写的时候即使不用do也没这么麻烦的啊,像这样:
然后才想起来其实这个表达式就是嵌套的 OTL
还是没有括号看起来顺眼些……但是由于优先级不同,Haskell里能省略的这些括号在Ruby里就省略不了。只好乖乖的写吧。
嘛,无论如何,有了Maybe类的定义后,我们就得到了传播Maybe::None的能力。像是把前面的1+2换成1+None,得到的就会是None:
或者写在一行上?
用Haskell写的话,不用do记法是
用do记法的话
嗯,看过maybe monad,那么list monad呢?
Ruby里的Enumerable模块其实就可以看成一个抽象的表,里面的select、inject、map/collect等方法都有函数式编程的对应物:filter、fold_left、map等。那干脆就把list monad的bind函数写在Enumerable里好了,像这样:
然后,例如说要求[1, 2]的每个元素分别与[3, 4, 5]的每个元素的乘积的列表:
呜,没想像中的好看 T T
即使不用list monad,直接用each来写看起来也差不多:
而在有专门的语法支持的语言里,这逻辑写起来就很优雅:
在Haskell里即使不用do记法也不难看:
回到开头C#的那个例子,用上面Ruby里的list monad来写的话,
感觉微妙……
有没有什么办法能让这monad在Ruby里更好看些?还是说我要求的过多了?
即使像LINQ的SelectMany那样把Bind写成多接受一个参数的版本,调用也还是会嵌套啊(虽然lambda表达式不必嵌套了)。我就是想少写点括号少写些缩进而已……
周末再读读《The Ruby Programming Language》来找找灵感好了。
对了,记个链接:MenTaLguY: Monads in Ruby
还没来得及读……
很好奇你所提到的yield1、yield2是什么语境下的?因为没见过,所以想多了解一些~
至于在Ruby里传入多于一个闭包,其实不是大问题吧?原本用yield的地方也可以用显式的block参数+.call来调用,要多个闭包的话就多收几个参数好了。像是Ruby里的Y组合子,可以简单实现为:
这段代码里一个&都没用到(当然我们知道lambda这个函数里是有&的……不过不管了),也一个yield都没用到,直接收了参数拿来调用,仅此而已。好吧这段代码里的lambda都是收一个参数的,不过多收几个也没啥差别?
至于说我这帖原本想写的东西,应该跟传入多个闭包没关系,而是跟嵌套定义的闭包有关系……但我傻了,用monad也不会解决闭包的嵌套的,除非弄个monadic syntax来掩盖这实现细节,像Haskell的do记法。
Umm...我没理解,请问yield1、yield2指的是什么?
通过LINQ,代码很简洁:
using System; using System.Linq; static class Program { static void Main(string[] args) { var booleanValues = new [] { true, false }; var equal = !(from a1 in booleanValues from a2 in booleanValues from a3 in booleanValues from b1 in booleanValues from b2 in booleanValues from b3 in booleanValues select (!((a1 && b1) || (a2 && b2) || (a3 && b3))) == (!(a1 && b1) && !(a2 && b2) && !(a3 && b3))) .Contains(false); Console.WriteLine(equal); // true } }
这段代码看起来应该算是比较直观的。不过……似乎又不太直观?
对许多人来说,或许显式用循环会直观得多:
using System; static class Program { static void Main(string[] args) { var booleanValues = new [] { true, false }; var equal = true; foreach (var a1 in booleanValues) { foreach (var a2 in booleanValues) { foreach (var a3 in booleanValues) { foreach (var b1 in booleanValues) { foreach (var b2 in booleanValues) { foreach (var b3 in booleanValues) { if ((!((a1 && b1) || (a2 && b2) || (a3 && b3))) != (!(a1 && b1) && !(a2 && b2) && !(a3 && b3))) { equal = false; break; } } if (!equal) break; } if (!equal) break; } if (!equal) break; } if (!equal) break; } if (!equal) break; } Console.WriteLine(equal); // true } }
但这代码好丑啊 =v=
好吧我作 弊了。就以上两个版本的代码来比较,它们实际的执行过程是不同的;LINQ的版本是会把所有可能性都算出来之后再看是否Contains(),因为Contains是一个eager operator,不像Select、Where那些是lazy的;循环版是遇到不相等的状况就直接退出循环了。不过反正两个版本算出来的结果都一样,用来对比也不算过分。
其实C#的foreach循环已经掩盖了许多细节,不需要显式用下标或者IEnumerator来遍历容器。不过我还是不喜欢在这种场景用显式的循环,主要是因为循环嵌套起来非常难看,搞不好就要超过屏幕的右边了。
之前说LINQ的版本看起来简洁,但未必很直观,是因为:多个from子句连在一起对应的函数是SelectMany,对IEnumerable<T>/IQueryable<T>而言这个LINQ运算符背后的概念则是list monad中的bind函数;其中的机理还是需要读些资料才能理解的。一看到monad这词很多人就要开始晕了吧? =w=
本来是想list monad在C#通过LINQ来使用可以这么简洁,那要是能在Ruby里也这样用就好了。但如标题所说,语言没有提供monad语法的时候,这玩儿写起来也不优雅。其实更关键的问题或许是没有typeclass的条件下monad无法提供统一的接口来提高抽象层次?不过我只想关心语法,也就是“看起来如何”的问题。
例如说,用Ruby来实现一个maybe monad:
class Maybe def initialize(val, has_val = true) @value, @has_value = val, has_val end def value raise 'Maybe::None has no value' unless @has_value @value end class << self def unit(val) new(val).freeze end end def bind @has_value ? (yield @value) : Maybe::None end def none? self == Maybe::None end def clone raise TypeError, "can't clone instance of Maybe" end def dup raise TypeError, "can't dup instance of Maybe" end None = Maybe.new(nil, false).freeze private_class_method :new, :allocate end
定义了Maybe类之后,可以这样用:
res1 = Maybe.unit(1). bind { |x| Maybe.unit(x + x) }. bind { |x| Maybe.unit(x * x) } #=> #<Maybe:0x34bc3e8 @has_value=true, @value=4>
看起来还不错,方法调用没有嵌套,都是串在一起的。
但这只不过是因为这一连串计算是从单一的来源得到数据的:那个“1”。假如要把一个“1”和一个“2”都用Maybe包装起来,然后要得到它们的和,那就变成:
one, two = [1, 2].map { |i| Maybe.unit i } res2 = one.bind { |x| two.bind { |y| Maybe.unit(x + y) } } #=> #<Maybe:0x35ece5c @has_value=true, @value=3>
于是bind的调用就嵌套起来了,郁闷 T T
我一时觉得纳闷,明明记得在Haskell里写的时候即使不用do也没这么麻烦的啊,像这样:
Just 1 >>= \x -> Just 2 >>= \y -> return (x + y)
然后才想起来其实这个表达式就是嵌套的 OTL
(Just 1) >>= (\x -> ((Just 2) >>= (\y -> (return (x + y)))))
还是没有括号看起来顺眼些……但是由于优先级不同,Haskell里能省略的这些括号在Ruby里就省略不了。只好乖乖的写吧。
嘛,无论如何,有了Maybe类的定义后,我们就得到了传播Maybe::None的能力。像是把前面的1+2换成1+None,得到的就会是None:
res3 = one.bind { |x| Maybe::None.bind { |y| Maybe.unit(x + y) } } #=> #<Maybe:0x316384 @has_value=false, @value=nil> res3.none? #=> true
或者写在一行上?
res3 = one.bind { |x| Maybe::None.bind { |y| Maybe.unit(x + y) } }
用Haskell写的话,不用do记法是
Just 1 >>= \x -> Nothing >>= \y -> return (x + y)
用do记法的话
do x <- Just 1 y <- Nothing return (x + y)
嗯,看过maybe monad,那么list monad呢?
Ruby里的Enumerable模块其实就可以看成一个抽象的表,里面的select、inject、map/collect等方法都有函数式编程的对应物:filter、fold_left、map等。那干脆就把list monad的bind函数写在Enumerable里好了,像这样:
module Enumerable def bind self.inject([]) { |acc, e| acc + (yield e) } end end
然后,例如说要求[1, 2]的每个元素分别与[3, 4, 5]的每个元素的乘积的列表:
[1, 2].bind { |x| [3, 4, 5].bind { |y| [x * y] } } #=> [3, 4, 5, 6, 8, 10]
呜,没想像中的好看 T T
即使不用list monad,直接用each来写看起来也差不多:
res = [] [1, 2].each { |x| [3, 4, 5].each { |y| res << (x * y) } } #=> res == [3, 4, 5, 6, 8, 10]
而在有专门的语法支持的语言里,这逻辑写起来就很优雅:
do x <- [1, 2] y <- [3, 4, 5] return (x * y) -- [3,4,5,6,8,10]
from x in new [] { 1, 2 } from y in new [] { 3, 4, 5 } select x * y //=> { 3, 4, 5, 6, 8, 10 }
在Haskell里即使不用do记法也不难看:
[1, 2] >>= \x -> [3, 4, 5] >>= \y -> return (x * y)
回到开头C#的那个例子,用上面Ruby里的list monad来写的话,
boolVals.bind { |a1| boolVals.bind { |a2| boolVals.bind { |a3| boolVals.bind { |b1| boolVals.bind { |b2| boolVals.bind { |b3| [(!((a1 && b1) || (a2 && b2) || (a3 && b3))) == (!(a1 && b1) && !(a2 && b2) && !(a3 && b3))] } } } } } }.all? { |b| b } #=> true
感觉微妙……
有没有什么办法能让这monad在Ruby里更好看些?还是说我要求的过多了?
即使像LINQ的SelectMany那样把Bind写成多接受一个参数的版本,调用也还是会嵌套啊(虽然lambda表达式不必嵌套了)。我就是想少写点括号少写些缩进而已……
周末再读读《The Ruby Programming Language》来找找灵感好了。
对了,记个链接:MenTaLguY: Monads in Ruby
还没来得及读……
评论
7 楼
RednaxelaFX
2009-03-31
ychael 写道
传入一个闭包嫌太少
很好奇你所提到的yield1、yield2是什么语境下的?因为没见过,所以想多了解一些~
至于在Ruby里传入多于一个闭包,其实不是大问题吧?原本用yield的地方也可以用显式的block参数+.call来调用,要多个闭包的话就多收几个参数好了。像是Ruby里的Y组合子,可以简单实现为:
irb(main):001:0> Y = lambda { |y| lambda { |f| lambda { |x| f[y[y][f]][x] } } } => #<Proc:0x02e9a154@(irb):1> irb(main):002:0> Fix = Y[Y] => #<Proc:0x02e9a190@(irb):1> irb(main):003:0> F = lambda { |fac| lambda { |x| 0 == x ? 1 : x * fac[x-1] } } => #<Proc:0x02e915a4@(irb):3> irb(main):004:0> factorial = Fix[F] => #<Proc:0x02e9a1cc@(irb):1> irb(main):005:0> factorial[4] => 24
这段代码里一个&都没用到(当然我们知道lambda这个函数里是有&的……不过不管了),也一个yield都没用到,直接收了参数拿来调用,仅此而已。好吧这段代码里的lambda都是收一个参数的,不过多收几个也没啥差别?
至于说我这帖原本想写的东西,应该跟传入多个闭包没关系,而是跟嵌套定义的闭包有关系……但我傻了,用monad也不会解决闭包的嵌套的,除非弄个monadic syntax来掩盖这实现细节,像Haskell的do记法。
6 楼
ychael
2009-03-30
传入一个闭包嫌太少
5 楼
RednaxelaFX
2009-03-30
ychael 写道
不太理解,是不是yield1,yield2这种?
Umm...我没理解,请问yield1、yield2指的是什么?
4 楼
ychael
2009-03-30
不太理解,是不是yield1,yield2这种?
3 楼
night_stalker
2009-03-13
幂集一般都可以用二进制数来对应,其他语言里也一样
写在Fixnum里只是为了方便一点而已
写在Fixnum里只是为了方便一点而已
2 楼
RednaxelaFX
2009-03-13
太强了!拜一下~~~
Fixnum可以这样用……太强了 XDD
不过我的原意是想尽量不用块结构,或者即便用也尽量不嵌套而是串连在一起。实际把代码写出来才发觉自己错了,原本想的办法的lambda表达式就是嵌套的。如果像LINQ的SelectMany那样多给一个参数或许能不嵌套,回头得试试。
Fixnum可以这样用……太强了 XDD
night_stalker 写道
Ruby是不能省掉块结束符号地!真想弄掉只能自己加工下再eval……
不过我的原意是想尽量不用块结构,或者即便用也尽量不嵌套而是串连在一起。实际把代码写出来才发觉自己错了,原本想的办法的lambda表达式就是嵌套的。如果像LINQ的SelectMany那样多给一个参数或许能不嵌套,回头得试试。
1 楼
night_stalker
2009-03-13
我(逃避抽象的实用主义者)觉得:怎样写比较短,在于如何穷举a1 a2 a3 b1 b2 b3
Ruby是不能省掉块结束符号地!真想弄掉只能自己加工下再eval……
class Fixnum %w[a1 a2 a3 b1 b2 b3].each_with_index do |name, idx| define_method name, do self & (1<<idx) == 0 ? false : true end end end 0b1000000.times do |n| n.instance_eval %q[ if !((a1&&b1) || (a2&&b2) || (a3&&b3)) != !(a1&&b1) && !(a2&&b2) && !(a3&&b3) puts 'blah' end ] end
Ruby是不能省掉块结束符号地!真想弄掉只能自己加工下再eval……
发表评论
-
Sun JDK1.4.2_28有TieredCompilation
2014-05-12 08:48 0原来以前Sun的JDK 1.4.2 update 28就已经有 ... -
IBM JVM notes (2014 ver)
2014-05-11 07:16 0Sovereign JIT http://publib.bou ... -
Java 8的lambda表达式在OpenJDK8中的实现
2014-02-04 12:08 0三月份JDK8就要发布首发了,现在JDK8 release c ... -
基于LLVM实现VM的JIT的一些痛点
2014-01-07 17:25 0同事Philip Reames Sanjoy Das http ... -
tailcall notes
2013-12-27 07:42 0http://blogs.msdn.com/b/clrcode ... -
《自制编程语言》的一些笔记
2013-11-24 00:20 0http://kmaebashi.com/programmer ... -
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22410(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局 (0): 拿在手上的是什么
2013-11-04 18:22 21510(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
Function.prototype.bind
2013-09-24 18:07 0polyfill http://stackoverflow. ... -
Java的instanceof是如何实现的
2013-09-22 16:57 0Java语言规范,Java SE 7版 http://docs ... -
struct做参数不能从寄存器传?
2013-08-28 23:33 0test test test struct Foo { i ... -
也谈类型: 数据, 类型, 标签
2013-08-18 01:59 0numeric tower http://en.wikiped ... -
SDCC 2012上做的JVM分享
2012-10-17 16:35 32662刚把在SDCC 2012做的JVM分享的演示稿上传了。 演示 ... -
运行时支持系统的“重量”
2012-10-12 16:08 0运行时支持系统的“重量” 好久没写博客了,可写的话题已经堆积 ... -
class?metaclass?meta-what?
2011-04-05 19:43 0http://en.wikipedia.org/wiki/Me ... -
“代码模式”与抽象
2010-10-28 15:21 0嗯,我是说“代码模式”,不是“设计模式”;这里指的是在给定的场 ... -
lvalue与rvalue
2010-09-03 00:40 0http://en.wikipedia.org/wiki/Va ... -
动态链接的“依据”
2010-02-09 09:54 0动态链接,意味着在生成的“东西”里留有符号信息,等到运行时再r ...
相关推荐
Monad入门,简介。英文版。介绍什么是Monad,以及如何使用Monad,还有如果自己定义Monad。
要使用此语法,您需要使用[%monad ...]扩展名包装一个序列表达式(即e1; e2 )。 [ % monad x < - [ 1 ; 2 ; 3 ]; y < - [ 3 ; 4 ; 5 ]; return (x + y) ] v <- e结合的一个monadic值e给一个变量v 。 ...
具有清晰一致语法的简单 monad 实现。 用法 一个 monad 有一个值,它被包裹起来。 它的值可以是任何东西:String、Module、Proc 等等……它把它的值作为唯一的参数,并且可以使用元素引用语法进行初始化: ...
Monad是一种抽象的编程构造,源自纯函数式编程语言,如Haskell和Scala,它允许开发者在处理计算流程时保持代码的简洁性和可读性。在Android-Monad项目中,开发者可以体验到Scala风格的编程语法,使得Android应用的...
Swift Monad 是一种编程概念,源于函数式编程语言,如 Haskell 和 Scala,被引入到苹果的 Swift 语言中,用于处理可变性和副作用。Monad 是一个抽象的概念,它提供了一种结构化的方式来组合操作,特别是在处理可能...
Monadless库与Cats库可以很好地协同工作,为开发者提供更丰富的Monad支持。 **ScalaJS和Monix的结合** ScalaJS是一个让Scala代码编译成JavaScript的工具,允许开发者在浏览器或Node.js环境中运行Scala程序。Monix...
通过理解单子,我们可以更好地理解和使用Haskell的IO系统,从而与现实世界进行交互。 文档首先对比了纯函数编程和命令式编程的特点,阐述了纯函数如何处理现实世界中的问题。接着,文章介绍了单子和其关键操作符(>>...
在这个详细参考中,我们将深入探讨 Haskell 的核心语法和特性,帮助你更好地理解和运用这一强大的编程工具。 1. **基本语法** - **变量与常量**:在 Haskell 中,变量名是区分大小写的,且默认是常量(不可变),...
Monad 是微软在早期提出的一种编程模型,主要用于解决 .NET Framework 中异步操作和资源管理的问题。Monad 是一种函数式编程的概念,它提供了一种结构化的方式来处理计算过程,特别是那些涉及副作用的操作,如输入/...
理解力Salmon使用fmap和flatmap的实现来提供do语法,该语法类似于Haskell中的do理解和Scala中的理解。 在Haskell中,monad理解如下: do a <- [ 1 , 2 , 3 ] let c = 5 b <- [ 4 , 5 ] return (a + b + c)...
Racket 中的 Monad,一种动态类型语言这个库展示了一种以动态类型语言处理 monad 的方法,包括一种实现返回类型多态的方法。 它开始是一个实验,记录在,查看动机和与其他方法的比较等。 代码使用的功能代替 Haskell...
如果你对Monad感兴趣,或者正在使用Hack编程,深入研究这个项目将帮助你提升对函数式编程和Monad的理解,从而更好地应对复杂的编程挑战。 总的来说,"monhacko"项目是探索Hack编程语言中Monad概念的一个实验性尝试...
在给定的文件内容中,我们主要探讨了编程中的MONAD概念,并涉及了编程语言Swift中的相关用法。MONAD是一种用于处理组合异步操作、集合、函数等计算的通用设计模式,它能够让我们把计算表达为一系列操作步骤,而不...
本章节探讨了如何利用Monad来模拟传统函数组合的方式,这有助于更好地理解和编写Haskell中的复杂逻辑。 ##### 示例: - **问题提出**(Va Question):提出了一些关于如何使用Monad进行函数组合的问题。 - **答案**...
首先,movie-monad 是使用Haskell编程语言编写的。Haskell是一种纯函数式编程语言,以其类型系统和静态类型著称,这使得代码更加可靠和可维护。使用Haskell开发视频播放器意味着movie-monad具有高度的模块化和可组合...
这使得开发者在使用Free Monad时可以获得更好的开发体验和工具支持。 **描述**提到的“一流Intellij支持”意味着这个库不仅提供了Free Monad的实现,还优化了与IntelliJ IDEA集成,使得IDE能够理解Free Monad的结构...
monad.js 为 NodeJS(或任何 CommonJS 实现)提供了简单的 monadic 数据类型。 也许 也许代表一个可能存在也可能不存在的值。 当一个值或函数的结果可能会或可能不会产生有意义的东西时,这是很自然的。 传统上, ...
Monad-ts是一个小型库,实现了一些关键的monad以及将它们链接到JavaScript和Typescript的流(管道)中的方法。 兼容Angular 2+ 。 。 内容 介绍 所有单子 也许 列表 状态 附加工具(类和功能) 异步流 流 投 克隆...
Nimonad 是一个专门为 Nim 语言设计的 Monad 库,旨在为这个高效、简洁的系统编程语言引入函数式编程的概念。Monad 是一种抽象计算模型,它在函数式编程中扮演着重要的角色,尤其是在处理可变状态和控制流时。Nim ...