在上一篇创建了我们的第一个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的更多相关文章

  1. 通过orderby关键字,LINQ可以实现升序和降序排序。LINQ还支持次要排序。

    通过orderby关键字,LINQ可以实现升序和降序排序.LINQ还支持次要排序. LINQ默认的排序是升序排序,如果你想使用降序排序,就要使用descending关键字. static void M ...

  2. Rafy 中的 Linq 查询支持(根据聚合子条件查询聚合父)

    为了提高开发者的易用性,Rafy 领域实体框架在很早开始就已经支持使用 Linq 语法来查询实体了.但是只支持了一些简单的.常用的条件查询,支持的力度很有限.特别是遇到对聚合对象的查询时,就不能再使用 ...

  3. C#8.0: 在 LINQ 中支持异步的 IAsyncEnumerable

    C# 8.0中,提供了一种新的IAsyncEnumerable<T>接口,在对集合进行迭代时,支持异步操作.比如在读取文本中的多行字符串时,如果读取每行字符串的时候使用同步方法,那么会导致 ...

  4. Monad 系列

    本系列是在学习Monad时在网上找到的一个老外的博客,作者是MikeHadlow,地址是mikehadlow.blogspot.com,  可惜国内访问不了.这个系列对Monad讲解的浅显易懂,而且有 ...

  5. 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外,现在还支持 ...

  6. C# 函数式编程:LINQ

    一直以来,我以为 LINQ 是专门用来对不同数据源进行查询的工具,直到我看了这篇十多年前的文章,才发现 LINQ 的功能远不止 Query.这篇文章的内容比较高级,主要写了用 C# 3.0 推出的 L ...

  7. Entity Framework 6 Recipes 2nd Edition(11-11)译 -> 在LINQ中调用数据库函数

    11-11. 在LINQ中调用数据库函数 问题 相要在一个LINQ 查询中调用数据库函数. 解决方案 假设有一个任命(Appointment )实体模型,如Figure 11-11.所示, 我们想要查 ...

  8. LinqToDB 源码分析——轻谈Linq查询

    LinqToDB框架最大的优势应该是实现了对Linq的支持.如果少了这一个功能相信他在使用上的快感会少了一个层次.本来笔者想要直接讲解LinqToDB框架是如何实现对Linq的支持.写到一半的时候却发 ...

  9. C#基础:LINQ 查询函数整理

    1.LINQ 函数   1.1.查询结果过滤 :where() Enumerable.Where() 是LINQ 中使用最多的函数,大多数都要针对集合对象进行过滤,因此Where()在LINQ 的操作 ...

随机推荐

  1. vmware Horizon 7 与远程桌面(mstsc)兼容性问题解决办法

    关于Horizon 7 Agent与远程桌面(mstsc)兼容性问题解决办法 在Horizon 7环境中,在桌面模板安装了Horizon Agent后,就无法直接通过微软的远程桌面(mstsc)工具连 ...

  2. python 生成HTmL报告页面 V1.3 修改字体颜色

    HTML报告V1.3 根据文字内容显示不同的字体颜色: 代码如下: # -*- coding=utf-8 -*- import time,os """ V1.2 1.生成 ...

  3. 【剑指Offer】55、链表中环的入口结点

      题目描述:   给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null.   解题思路:   本题是一个比较典型的链表题目,难度适中.首先,对于大多人来说,看到这道题是比较开心的 ...

  4. 【剑指Offer】32、把数组排成最小的数

      题目描述:   输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323.   ...

  5. 51nod1134 最长递增子序列【动态规划】

    给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递增的) 例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10. Input 第1行:1个数N ...

  6. BABEL转码解惑

    众所周知,解决Nodejs异步问题的终极方案就是使用async/await方案,但是每次在项目中配置都会或多或少有些问题,每次都会被几个组件 babel-core babel-polyfill bab ...

  7. C#关键字的个人理解与注释

    C#关键字注释:abstract:抽象as:类型转换(返回转换结果)base:基类bool:布尔类型break:条件中断语句byte:字节case:条件语句catch:异常捕获后执行char:16 位 ...

  8. Locally managed (LMT) vs. Dictionary managed (DMT) tablespace

    The LMT is implemented by adding the extent management local clause to the tablespace definition syn ...

  9. win10使用WampServer部署magento

     1.安装wampserver及php.apache.mySQL组件,访问http://www.wampserver.com/en/#download-wrapper,下载以下文件并依次安装:     ...

  10. SEO 爬虫原理介绍

    一篇关于网络爬虫程序的一些原理及体系结构纯技术文章,一些地方可能不会看的非常明确.对于SEO行业,常常和搜索引擎及其爬虫程序打交道,细致浏览下,一些不清楚而自己又非常想了解的地方,能够借助搜索来需找相 ...