C#中的Monads-为什么Bind实现需要传递一个函数来返回一个monad?分享
时间:2023-04-10 17:50:13
C#
C#中的Monads-为什么Bind实现需要传递一个函数来返回一个monad?我在C#中看到的大多数monad示例都是这样写的:publicstaticIdentityBind(thisIdentitya,Funcfunc){returnfunc(a.Value);参见例如http://mikehadlow.blogspot.com/2011/01/monads-in-c-3-creating-our-first-monad.html。问题是,要求func返回一个Identity有什么意义?如果我使用以下定义:publicinterfaceIValue{publicIValueBind(Funcfunc)}那么我实际上可以对Lazy、Task、Maybe等使用相同的func而无需实际依赖实现IValue实际类型。我在这里错过了什么重要的事情?首先,考虑组合的概念。我们可以很容易地将组合表达为对委托的操作:publicstaticFuncCompose(thisFuncf,Funcg){returnx=>f(g(x));所以,如果我有一个函数g是(intx)=>x.ToString(),函数f是(strings)=>s.Length那么我可以创建一个函数h是(intx)=>x.ToString().Length通过调用f。撰写(g)(intx)=>x.ToString().Length。这应该很清楚。现在假设我有一个从T到Monad的函数g和一个从U到Monad的函数f。我希望编写一个方法,将这两个返回monad的函数组合成一个接受T并返回Monad的函数。所以我试着写:publicstaticFunc>Compose(thisFunc>f,Func>g){returnx=>f(g(x));}不起作用。g返回一个Monad但f需要U我有办法将U包装成Monad但我没有办法将其“打开”。但是,如果我有一个方法publicstaticMonadBind(thisMonadm,Func>k){whatever}那么我可以编写一个方法来组合两个返回monad的方法:publicstaticFunc>Compose(thisFunc>f,Func>g){returnx=>Bind(g(x),f);这就是为什么Bind需要一个从T到Monad的函数——因为事情的重点是能够获得从T到Monad和从U到Monad的函数g函数f将它们组合成一个从T到Monad的函数h。如果你想要一个从T到U的函数g和一个从U到Monad的函数f,那么你首先不需要Bind。只需正常编写函数即可从T到Monad!Bind的全部意义就是解决这个问题;如果你在这个问题上徘徊,那么你首先不需要Bind。更新:在大多数情况下,我想将T中的函数g和U到V中的函数f组合成一个Monad,我想你想将它组合成一个从T到V的函数。但你不能保证这样的操作被定义!例如,将“Maybemonad”作为monad,在C#中表示为T?。假设g为(intx)=>(double?)null并且函数f为(doubley)=>(decimal)y。您如何将f和g组合成一个接受int并返回不可为null的小数的方法?没有“展开”来将可为空的双精度值打包成f可以采用的双精度值!您可以使用Bind将f和g组合成一个接受int并返回可为null的小数的方法:publicstaticFunc>Compose(thisFuncf,Func>g){returnx=>Bind(g(x),x=>单位(f(x)));其中Unit是一个接受V并返回Monad的函数。但是如果g返回一个monad而f不返回一个monad那么就没有f和g的组合-不能保证有一种方法可以从monad的实例返回到“unwrap”类型。也许在一些monad的情况下总是有——比如Lazy。也许有时就像一个“也许”的单子。通常有一种方法可以做到,但不要求您可以做到。顺便说一下,请注意我们如何将“Bind”用作新创作的瑞士军刀。绑定可以做任何事情!例如,假设我们对序列monad有一个Bind操作,我们在C#中对IEnumerable类型调用“SelectMany”:staticIEnumerableSelectMany(thisIEnumerablesequence,Func>f){foreach(Uuinsequence)foreach(Vv在f(u))中产生回报v;您可能还有一个序列运算符:staticIEnumerableWhere(thisIEnumerablesequence,Funcpredicate){foreach(Aiteminsequence)if(predicate(item))yieldreturnitem;您真的需要在Where中编写该代码吗?不!您可以完全使用“Bind/SelectMany”来构建它:staticIEnumerableWhere(thisIEnumerablesequence,Funcpredicate){returnsequence.SelectMany((Aa)=>predicate(a)?newA[]{a}:newA[]{});}高效的?不,但没有什么是Bind/SelectMany做不到的。如果您真的想要,您可以构建除SelectMany之外的所有LINQ序列运算符。以上是C#学习教程:MonadsinC#-为什么Bind实现需要传递一个函数返回一个monad?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: