还记得我们上一篇delegate类型的parser吗 ,在开始本篇之前,强烈建议你复习一下这个parser定义 

public delegate Maybe<Tuple<T,string>>Parser<T>(string input)

还记得我们组合这些parser的不易吗?现在我们采用新的方式将parser转换为Monad, 我们已经知道了如何将泛型类和泛型接口转换成Monad, 同样的也可以将委托转换成Monad

首先我们实现一个ToParser方法, 它相当简单,只返回一个不消耗任何输入字符串的parser

public static Parser<T>ToParser(this T value)
{
return input=>new Just<Tuple<T,string>>(Tuple.Create(value,input))
}

接下来我们需要一个Bind方法, 回想下Bind方法的签名,记住所有的Monad Bind方法签名时一样的

public static Parser<B> Bind<A,B> (this Parser<A>a, Func<A,Parser<B>>func)()

现在我们一步步实现Bind,首先看下返回类型 Parser<B>.记住Parser<B>是一个参数为string 返回类型为Maybe<Tuple<B,string>>的函数,所以我们需要为这个函数返回一个lambda表达式

public static Parser<B>Bind<A,B>(this Parser<A> a, Func<A,Parser<B>func>)
{
input=>
{ //......
}
}

这个lambda需要返回Maybe<Tuple<B,string>>, 我们可以通过调用func返回返回Parser<B>,然后调用Parser<B>返回它:

public static Parser<B>Bind<A,B>(this Parser<A>a, Func<A,Parser<B>>func)
{
return input=>
{
var bparser=func(???); return bparser(???);
};
}

我们需要一个参数A调用func, 我们可以调用a得到它的返回值,然后从中取出A来:

public static Parser<B> Bind<A,B>(this Parser<A>a, Func<A,Parser<B>>func)
{
return input=>
{ var aMaybe=a(input); var aResult=aMaybe as Just<Tuple<A,string>>; //short circuit if parse fails if(aResult == null) return new Nothing<Tuple<B,string>>(); var aValue=aResult.Value.Item1; var bParser=func(aValue); return bParser(???);
}
}

注意我们短路了解析过程,如果有一个parser失败,这意味着任何解析器组合都会返回Nothing,如果其中一个解析器不能解析它的输入.

最后我们需要一个string 作为bParser的输入,这个值可以从parser a的返回结果里得到:

public static Parser<B> Bind<A,B>(this Parser<A>a, Func<A,Parser<B>>func)
{
return input=>
{
var aMaybe=a(input); var aResult=aMaybe as Just<Tuple<A,string>>; //short circuit if parse fails if(aResult == null) return new Nothing<Tuple<B,string>>(); var aValue=aResult.Value.Item1; var sString=aResult.Value.Item2; var bParser=func(aValue); return bParser(sString);
}
}

我们已经创建了一个Monad parser,为了使用linq的语法,我们需要实现SelectMany ,

现在我们可以只用下面三行代码来实现我们的Hello World parser.

public static Parser<C>SelectMany<A,B,C>(this Parser<A>a, Func<A,Parser<B>>func, Func<A,B,C>select)
{
a.Bind(aval=>func(aval).Bind(bval=>select(aval,bval).ToParser()));
}

var helloWorldParser=from hello in "Hello".Find()

                                    from world in "World".Find()

                                    select new (Hello=hello, World=world);

var result=helloWorldParser("HelloWorld");

Console.WriteLine(result.AsString(x=>x.Hello));

Console.WriteLine(result.AsString(x=>x.World));

//outputs

//Hello

//World

这个实现充满美感,希望你能开始了解怎样用Monad 创建复杂的逻辑,如果你想深入了解Monad parser, Nicholas Blumhardt实现的project Sprache可供参考: https://github.com/sprache/Sprache

其他Monad资源参考:

https://github.com/phenixyu/csharp-monad

将我们的parser转换成Monad的更多相关文章

  1. Gson将字符串转换成JsonObject和JsonArray

    以下均利用Gson来处理: 1.将bean转换成Json字符串: public static String beanToJSONString(Object bean) { return new Gso ...

  2. 【HIVE】sql语句转换成mapreduce

    1.hive是什么? 2.MapReduce框架实现SQL基本操作的原理是什么? 3.Hive怎样实现SQL的词法和语法解析? 连接:http://www.aboutyun.com/thread-20 ...

  3. Python 爬虫:把廖雪峰教程转换成 PDF 电子书

    写爬虫似乎没有比用 Python 更合适了,Python 社区提供的爬虫工具多得让你眼花缭乱,各种拿来就可以直接用的 library 分分钟就可以写出一个爬虫出来,今天尝试写一个爬虫,将廖雪峰老师的 ...

  4. Java对象转换成xml对象和Java对象转换成JSON对象

    1.把Java对象转换成JSON对象 apache提供的json-lib小工具,它可以方便的使用Java语言来创建JSON字符串.也可以把JavaBean转换成JSON字符串. json-lib的核心 ...

  5. Gson解析json字符串、json数组转换成对象

    实体类: public class Product { private int id; private String name; private String date; public int get ...

  6. 自制 Python小工具 将markdown文件转换成Html文件

    今天看到了一个Python库,名为markdown.瞬间就给了我一个灵感,那就是制作一个将markdown文件转换成html文件的小工具. 我的实验环境 操作系统: Windows 7 64位 旗舰版 ...

  7. 用Python将word文件转换成html(转)

    用Python将word文件转换成html   序 最近公司一个客户大大购买了一堆医疗健康方面的科普文章,希望能放到我们正在开发的健康档案管理软件上.客户大大说,要智能推送!要掌握节奏!要深度学习!要 ...

  8. python3将docx转换成pdf,html文件,pdf转doc文件

    直接上代码 # -*- encoding:utf-8 -*- """ author:lgh 简单的doc转pdf,html,pdf转doc脚本 依赖库pdfminer3k ...

  9. 将字符串转换成xml并取得对应的值

    如数据库中有一个字段保存了xml格式的一串字符串: <?xml version="1.0" encoding="utf-16"?><Array ...

随机推荐

  1. vue系列---identify(生成图片验证码)插件

    identify 这是一个vue的插件,使用canvas来生成图形验证码. 具体参数如下: identify.vue组件(主要用于定义参数和方法) <template> <div c ...

  2. git_安装与配置

    安装 windows平台安装 在windows平台安装git,需要下载exe.文件,下载地址:https://gitforwindows.org/,双击下载的.exe文件,按照提示进行安装,安装完成后 ...

  3. 关于Arrays协助类中的排序方法

    sort方法是优化的快速排序,不稳定. paralleSort是多线程排序,稳定,但是有长度限制.

  4. C#中为什么字段设为只读依然可以在构造函数中为它赋值

    因为只读是为了保证在类的 实例 被 创建后 ,当前属性不能被改变 构造函数中实例还没创建完成,所以依然可以改变

  5. Labview学习笔记(一)

    一.概述 Labview是一种工业标准图形化编程工具,主要用于开发测试.测量与控制系统,拥有一个可以完成任何编程任务的庞大函数库,包括数据采集.GPIB.串口控制.数据分析.数据显示及数据存储等. L ...

  6. 【剑指Offer】19、顺时针打印矩阵

      题目描述:   输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依 ...

  7. 51nod1289 大鱼吃小鱼

    有N条鱼每条鱼的位置及大小均不同,他们沿着X轴游动,有的向左,有的向右.游动的速度是一样的,两条鱼相遇大鱼会吃掉小鱼.从左到右给出每条鱼的大小和游动的方向(0表示向左,1表示向右).问足够长的时间之后 ...

  8. 08.Web服务器-4.Web服务器动态资源请求

    1 浏览器请求动态页面过程 2 WSGI 怎么在你刚建立的Web服务器上运行一个Django应用和Flask应用,如何不做任何改变而适应不同的web架构呢? 在以前,选择 Python web 架构会 ...

  9. 理解__builtin_clz特性

    a.c: /************************************************************************* * File: a.c * Brief: ...

  10. find结合rm删除大量文件

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://navarro.blogbus.com/logs/31502374.html 例:删除/home/raven下,包括子目录 ...