Linq怎么支持Monad
在上一篇创建了我们的第一个Monad, Identity<T>. 我们确定了类型要变成Monad, 它必须有一个type constructor(Identity<T>), 和两个方法,Bind与ToIdentity
//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创建
Linq怎么支持Monad的更多相关文章
- 通过orderby关键字,LINQ可以实现升序和降序排序。LINQ还支持次要排序。
通过orderby关键字,LINQ可以实现升序和降序排序.LINQ还支持次要排序. LINQ默认的排序是升序排序,如果你想使用降序排序,就要使用descending关键字. static void M ...
- Rafy 中的 Linq 查询支持(根据聚合子条件查询聚合父)
为了提高开发者的易用性,Rafy 领域实体框架在很早开始就已经支持使用 Linq 语法来查询实体了.但是只支持了一些简单的.常用的条件查询,支持的力度很有限.特别是遇到对聚合对象的查询时,就不能再使用 ...
- C#8.0: 在 LINQ 中支持异步的 IAsyncEnumerable
C# 8.0中,提供了一种新的IAsyncEnumerable<T>接口,在对集合进行迭代时,支持异步操作.比如在读取文本中的多行字符串时,如果读取每行字符串的时候使用同步方法,那么会导致 ...
- Monad 系列
本系列是在学习Monad时在网上找到的一个老外的博客,作者是MikeHadlow,地址是mikehadlow.blogspot.com, 可惜国内访问不了.这个系列对Monad讲解的浅显易懂,而且有 ...
- db4o发布7.2,出现.NET 3.5版本,支持LINQ
db4o发布7.2,出现.NET 3.5版本,支持LINQ Db4Object刚刚发布了db4o的7.2beta,除了以前支持如下的平台:.NET 1.1,.NET 2.0,Mono外,现在还支持 ...
- C# 函数式编程:LINQ
一直以来,我以为 LINQ 是专门用来对不同数据源进行查询的工具,直到我看了这篇十多年前的文章,才发现 LINQ 的功能远不止 Query.这篇文章的内容比较高级,主要写了用 C# 3.0 推出的 L ...
- Entity Framework 6 Recipes 2nd Edition(11-11)译 -> 在LINQ中调用数据库函数
11-11. 在LINQ中调用数据库函数 问题 相要在一个LINQ 查询中调用数据库函数. 解决方案 假设有一个任命(Appointment )实体模型,如Figure 11-11.所示, 我们想要查 ...
- LinqToDB 源码分析——轻谈Linq查询
LinqToDB框架最大的优势应该是实现了对Linq的支持.如果少了这一个功能相信他在使用上的快感会少了一个层次.本来笔者想要直接讲解LinqToDB框架是如何实现对Linq的支持.写到一半的时候却发 ...
- C#基础:LINQ 查询函数整理
1.LINQ 函数 1.1.查询结果过滤 :where() Enumerable.Where() 是LINQ 中使用最多的函数,大多数都要针对集合对象进行过滤,因此Where()在LINQ 的操作 ...
随机推荐
- 微信小程序例子-保存图片到手机相册
微信小程序例子-保存图片到手机相册 1.关键代码 1)WXML文件 2)JS文件 saveImgToPhotosAlbumTap: function(){ // 图片必须是 https 的 var I ...
- 小程序text组件内部上边距的问题
index.wxml: <view class="slogan"> <text> 建立跨文化的全球视野,做世界公民 </text> </v ...
- java操作Excel的poi 遍历一个工作簿
遍历一个工作簿 package com.java.poi; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.h ...
- day35-2 类的三大特性---多态,以及菱形继承问题
目录 菱形继承问题 经典类 新式类 菱形继承 大招 多态与多态性 多态 多态性 多态在Python中的体现 鸭子类型(重要) 结论 菱形继承问题 经典类 没有继承object类的就是经典类,只有Pyt ...
- 【转载】java中的反射
主要介绍以下几方面内容 理解 Class 类 理解 Java 的类加载机制 学会使用 ClassLoader 进行类加载 理解反射的机制 掌握 Constructor.Method.Field 类的用 ...
- GDI 画刷(10)
创建画刷 调用 CreateSoildBrush.CreateHatchBrush.CreateBrushIndirect 函数可以创建画刷. CreateSoildBrush:创建实心画刷: Cre ...
- 51nod1185 威佐夫游戏 V2【博弈论】
有2堆石子.A B两个人轮流拿,A先拿.每次可以从一堆中取任意个或从2堆中取相同数量的石子,但不可不取.拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出2堆石子的数量, ...
- Django-xadmin+django-import-export导入导出的实现
转载自:https://blog.csdn.net/zcyuefan/article/details/77748850 1. 需求vs现状1.1 需求要求做一个ERP后台辅助管理的程序,有以下几项基本 ...
- Educational Codeforces Round 35 B/C/D
B. Two Cakes 传送门:http://codeforces.com/contest/911/problem/B 本题是一个数学问题. 有a个Ⅰ类球,b个Ⅱ类球:有n个盒子.将球放入盒子中,要 ...
- 利用Socket 客户端---->服务端 传送文件到指定路径,并返回一个友好的回馈
首先盲写的一个传输文件的方法,但测试发现了一个非常不容易发现的问题,这里先说明一下. 错误的代码如下: package com.TCP.java; import java.io.File; impor ...