还记得我们上一篇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. OAuth密码模式说明(resource owner password credentials)

    用户向客户端(third party application)提供用户名和密码. 客户端将用户名和密码发给认证服务器(Authorization server),向后者请求令牌(token). 认证服 ...

  2. XML-20100: (Fatal Error) Expected ';'. xml转word 导出时异常

    因为数据中包含特殊字符.需要进行转译. < < 小于号 > > 大于号 & & 和 &apos; ’ 单引号 " " 双引号 XML ...

  3. Match 基因匹配 题解(From luoguBlog)

    N<=20000!N2的LCS要原地爆炸. 去您妈的优化考场上有分就行TLE60真香嘿嘿嘿 然而这显然是个板子只不过像我这样见识短浅的蒟蒻不知道罢了 正解: 某大佬的博客 转化为lis后二分 复 ...

  4. MQTTnet 的Asp.Net Core 认证事件的扩展

    MQTTnet 的数据接收 连接 等事件都很丰富, 唯独客户端连接验证不能依赖注入也不能很舒服的使用事件的方式, 因此MQTTnet.AspNetCoreEx 就出现了. 示例如下:在  public ...

  5. res对象json,redirect

    1.res.json() var express=require('express'); var app=express(); app.get('/',function(req,res){ //返回j ...

  6. Vue select默认选中第一个

    <td> <select v-model="selectWare"> <option selected="selected" va ...

  7. 【剑指Offer】44、反转单词序列

      题目描述:   牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,&qu ...

  8. 松哥整理了 15 道 Spring Boot 高频面试题,看完当面霸

    什么是面霸?就是在面试中,神挡杀神佛挡杀佛,见招拆招,面到面试官自惭形秽自叹不如!松哥希望本文能成为你面霸路上的垫脚石! 做 Java 开发,没有人敢小觑 Spring Boot 的重要性,现在出去面 ...

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

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

  10. MySQL 存储过程的异常处理

    mysql> mysql> delimiter $$ mysql> mysql> CREATE PROCEDURE myProc     ->     (p_first_ ...