Linq怎么支持Monad
2016-06-27 23:30
351 查看
在上一篇创建了我们的第一个Monad, Identity<T>. 我们确定了类型要变成Monad, 它必须有一个type constructor(Identity<T>), 和两个方法,Bind与ToIdentity
我也提到了在C#里 Bind有个不同的名字,SelectMany,它是为IEnumerable<T>定义的扩展方法, 如你所知,IEnumerable<T>也是一个Monad,实际上它是C#里Monad的代表.
今天我们来看下如何为Identity<T>实现SelectMany, 并且去掉繁琐的lambda表达式
Linq要求我们写一个函数来结合Bind和To****的功能,SelectMany,SelectMany签名必须如下:
它看起来像Bind函数,只是多了一个select参数,它以A,B为参数,返回C。 并且有一个不同的返回类型Identity<C>,替代Identity<B>. 如果你的amplified实现了SelectMany方法,在执行Linq的"from x in y"表达式时会转换为SelectMany的调用.
让我们将SelectMany实现为一个扩展方法:
现在要根据参数类型来写出实现,首先我们知道要返回Identity<C>, 只有select Func可以返回C,我们可以调用ToIdentity将C转换为Identity<C>
传什么给select呢, 第一个参数是A,我们可以调用a.Value得到A, 第二个参数B,我们可以通过Bind函数得到B
让我们展开Bind函数,在这里Bind并没有多大用
我们已经为Identity<T>实现了SelectMany. 现在我们可以用Linq语法替换我们上一篇的lambda表达式:
是不是清晰很多?通过新视角看Linq和Monad, 我们可以把"from x in y"看做是Monad式的赋值,将将右侧的amplified value 赋值给左侧的unamplified type。
实际上你可以对任何WhatEver<T>使用Linq语法,而不仅仅是IEnumerable<T>。如果你想使用其他linq 语法如where,let,join等,你必须实现对应的方法, 他们都可以使用Bind创建
//a function Bind, allows us to compose Identity returning functions public static Identity<B> Bind<A,B>(this Identity<A>a, Func<A,Identity<B>func>) { return func(a.Value); } public static Identity<T>ToIdentity<T>(tis T Value) { return new Identity<T>(value); }
我也提到了在C#里 Bind有个不同的名字,SelectMany,它是为IEnumerable<T>定义的扩展方法, 如你所知,IEnumerable<T>也是一个Monad,实际上它是C#里Monad的代表.
今天我们来看下如何为Identity<T>实现SelectMany, 并且去掉繁琐的lambda表达式
Linq要求我们写一个函数来结合Bind和To****的功能,SelectMany,SelectMany签名必须如下:
Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func,Func<A,B,C>select)
它看起来像Bind函数,只是多了一个select参数,它以A,B为参数,返回C。 并且有一个不同的返回类型Identity<C>,替代Identity<B>. 如果你的amplified实现了SelectMany方法,在执行Linq的"from x in y"表达式时会转换为SelectMany的调用.
让我们将SelectMany实现为一个扩展方法:
public static Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func, Func<A,B,C>select) { return ??? }
现在要根据参数类型来写出实现,首先我们知道要返回Identity<C>, 只有select Func可以返回C,我们可以调用ToIdentity将C转换为Identity<C>
public static Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func, Func<A,B,C>select) { return select(???).ToIdentity(); }
传什么给select呢, 第一个参数是A,我们可以调用a.Value得到A, 第二个参数B,我们可以通过Bind函数得到B
public static Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func, Func<A,B,C>select) { return (a.Value,a.Bind(func).Value).ToIdentity(); }
让我们展开Bind函数,在这里Bind并没有多大用
public static Identity<C>SelectMany<A,B,C>(this Identity<A>a,Func<A,Identity<B>>func, Func<A,B,C>select) { return select(a.Value,func(a.Value).Value).ToIdentity(); }
我们已经为Identity<T>实现了SelectMany. 现在我们可以用Linq语法替换我们上一篇的lambda表达式:
var result="Hello World!".ToIdentity().Bind(a=> 7.ToIdentity().Bind(b=> (new DateTime(2010,1,11)).ToIdentity().Bind(c=> (a+", "+b.ToString()+", "+c.ToShortDateString()) .ToIdentity()))); var result=from a in "Hello World".ToIdentity() from b in 7.ToIdentity() from c in (new DateTime(2010,1,11)).ToIdentity() select a+", "+b.ToString()+", "+c.ToShortDateString(); Console.WriteLine(result.Value);
是不是清晰很多?通过新视角看Linq和Monad, 我们可以把"from x in y"看做是Monad式的赋值,将将右侧的amplified value 赋值给左侧的unamplified type。
实际上你可以对任何WhatEver<T>使用Linq语法,而不仅仅是IEnumerable<T>。如果你想使用其他linq 语法如where,let,join等,你必须实现对应的方法, 他们都可以使用Bind创建
相关文章推荐
- 09.Java 集合 - LinkedHashMap
- android图片加载库Glide
- android图片加载库Glide
- android图片加载库Glide
- 3Sum Closest
- 查看Nginx、apache、MySQL和PHP的编译参数
- Objective-C学习笔记
- View绘制之layout过程
- linux命令——scp
- 创建我们第一个Monad
- python安装与使用
- php 数组
- linux的那些事(1)
- VIJOS 1278 My Story Your Song-雨天
- php 源码解析--count
- mysql通过binlog恢复数据
- sencha 打包
- Android中asset文件夹和raw文件夹区别
- 自定义动画状态栏文字
- HTML5音视频播放(Video,Audio)和常见的坑处理