还记得我们上一篇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. jquery-pjax使用说明

    pjax = pushState + ajax .--. / \ ## a a ( '._) |'-- | _.\___/_ ___pjax___ ."\> \Y/|<'. '. ...

  2. react新版本生命周期

    给componentWillMount componentWillReceiveProps componentWillUpdate生命周期加上UNSAFE_前缀,表明其不安全性,并将在未来版本将其移除 ...

  3. .Net Core 中X509Certificate2 私钥保存为 pem 的方法

    在自己签发CA证书和颁发X509证书时,私钥通过下面的方法保存为PEM 相关代码可以已经提交在了 https://github.com/q2g/q2g-helper-pem-nuget/pull/13 ...

  4. Java设计模式之JDK动态代理原理

    动态代理核心源码实现public Object getProxy() { //jdk 动态代理的使用方式 return Proxy.newProxyInstance( this.getClass(). ...

  5. mysql修改原始密码

    后期修改数据库用户的密码初始密码为自动生成,我们需要情况原始密码,再修改密码,mysqldmin -u root 只能用在修改为原始密码之后使用systemctl stop mysqldvim /et ...

  6. BZOJ 3531: [Sdoi2014]旅行 权值线段树 + 树链剖分

    Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰 ...

  7. DataInputStream 数据类型数据输入输出流

    package IOliu; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileI ...

  8. Educational Codeforces Round 35 B/C/D

    B. Two Cakes 传送门:http://codeforces.com/contest/911/problem/B 本题是一个数学问题. 有a个Ⅰ类球,b个Ⅱ类球:有n个盒子.将球放入盒子中,要 ...

  9. QT中tableview不能更新数据,why?

    model->select(); //model->removeColumn(0);++++++++++++++++++++ //model->setHeaderData(model ...

  10. Nginx学习总结(2)——Nginx手机版和PC电脑版网站配置

    考虑到网站的在多种设备下的兼容性,有很多网站会有手机版和电脑版两个版本.访问同一个网站URL,当服务端识别出用户使用电脑访问,就打开电脑版的页面,用户如果使用手机访问,则会得到手机版的页面. 1.判断 ...