介绍一个简单的Parser
我们已经学习了怎样创建一个简单的Monad, MaybeMonad, 并且知道了它如何通过在 Bind函数里封装处理空值的逻辑来移除样板式代码. 正如之前所说的,我们可以在Bind函数中封装更复杂的逻辑. 下面给出一个更复杂更典型的Monad例子,一个解析器Monad. 在本篇将要介绍一个解析器,在之后的篇幅里将会把解析器转换成一个 Monad.
首先我们思考解析器要完成什么功能,它接受一个输入,通常是一些文本,然后输出期望的结果. 因此一个CSV解析器将会接受一个文本文件,输出行和列的数据,并带有数据类型. 我们可以把parser抽象成一个函数 ,它接受一个string,返回某种类型 T:
Func<string,T>
将一个大的任务分解成小的任务实现通常会更简单,所以如果我们能同坐组合很多小的解析器来构建我们的解析器会更好. 每个小的解析器可能会消耗部分字符串,所以我们可以定义函数接受一个 string, 返回 T 和匹配后剩余的字符串
Func<string, Tuple<T,string>>
Tuple是在.Net4里引入的新类型, 你可以用自定义类型替代。
我们的解析器可能并不能正确解析输入的字符串,因此我们还需要能处理解析失败的情况, 这里可以使用我们已定义的 Maybe 类型
Func<string, Mayb<Tuble<T,string>>>
现在来创建一个比较简单的解析器, 它匹配字符串"Hello":
public static Maybe<Tuple<T,string>>FindHello(string input)
{
return input.StartWith("hello") ?new Just<Tuple<string,string>>(Tuple.Create("Hello",input.Skip("Hello".Length).AsString())) :(Maybe<Tuple<string,string>>)new Nothing<Tuple<string,string>>();
}
如果输入的字符串中包含"Hello",将会返回"Hello"和剩余的字符串
var result=Parsers.FindHello("Hello world");
var justResult= result as Just<Tuple<string,string>>;
Console.WriteLine("justResult.Value.Item1={0}",justResult.Value.Item1);
//justResult.Value.Item1=Hello
Console.WriteLine("justResult.Value.Item2={2}",justResult.Value.Item2);
//justResult.Value.Item2=World
如果我们输入"GoodBye" ,它将会返回Nothing:
var result2=Parsers.FindHello("Goodbye world");
Console.WriteLine("resulte2={0}",result2);
//result2=Nothing
通过创建一个可以解析任何字符串的解析器工厂,我们可以使我们的解析器更优美, 首先定义一个delegate:
public delegate Maybe<Tuple<T,string>>Parser<T>(string input)
现在定义Find,写在扩展方法里:
public static Parser<string>Find(this string stringToFind)
{
return input=> input.StartsWith(stirngToFind)
?new Just<Tuple<string,string>>(Tuple.Create(stringToFind,input.Skip(stringToFind.Length).AsString()))
:(Maybe<Tuple<string,string>>)new Nothing<Tuple<string,string>>();
}
这是一个高阶函数,它返回一个函数,就是我们的解析器, 注意我们的解析器是一个delegate。
现在我们可以用它创建一些解析器,比如一个"Hello" 解析器和一个"World"解析器
var helloParser= "Hello".Find(); var worldParser="World".Find();
我们加一个扩展方法方便把解析结果转换成string:
public static string AsString<T>(this Maybe<Tuple<T,string>>parseResult, Func<T,string>unwrap)
{
var justParseResult= parseResult as Just<Tuple<T,string>>; return (justParseResult != null ?unWrap(justParseResult.Value.Item1)) :"Nothing";
}
现在我们用我们的helloParser 和 worldParser来解析字符串 :
var result =helloParser("Hello World").AsString(s=>s);
Console.WriteLine("result = {0}", result);
//result = Hello
var result2= worldParser("World Hello").AsString(s=>s);
Console.WriteLine("result2={0}",result2);
//result=World
我们怎么能把这两个parser结合起来创建一个"HelloWorld"的parser呢,这里有一个生硬的实现:
Parser<Tuple<string,string>>helloWorldParser=input=>
{
var helloResult= helloParser(input) as Just<Tuple<string,string>>; if(helloResult == null) return new Noting<Tuple<Tuple<string,string>,string>>(); var worldResult= worldParser(helloResult.Value.Item2) as Just<Tuple<strin,string>>; if(worldResult == null) return new Noting<Tuple<Tuple<string,string>,string>>(); return new Just<Tuple<Tuple<string,string>,string>>(Tuple.Create( Tuple.Create(helloResult.Value.Item1,worldResult.Value.Item1),worldResult.Value.Item2)); }; var result3=helloWorldParser("HelloWorld").AsString(s=>s.Item1 + " " + s.Item2); Console.WriteLine("result3 = {0}",result3); //result=Hello World
这样写非常繁琐,假如我们要组合更复杂的解析器,比如CSV解析器,将会非常令人头疼.但是不要担心,在下一篇我们将会把我们的解析器转换成Monad, 并以非常简单的方式组合他们
介绍一个简单的Parser的更多相关文章
- 安全小测试:介绍一个简单web安全知识测试的网站
https://websecurity.firebaseapp.com/ 一次测试一共7道题,最后有答案,可以反复做,每次随机抽题
- 自己动手实现一个简单的JSON解析器
1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...
- Web开发之tomcat配置及使用(环境变量设置及测试,一个简单的web应用实例)
Tomcat的配置及测试: 第一步:下载tomcat,然后解压到任意盘符 第二步:配置系统环境变量 tomcat解压到的D盘 (路径为: D:\tomcat), 配置环境变量: 启动tomcat需要两 ...
- 一个简单的基于 DirectShow 的播放器 1(封装类)
DirectShow最主要的功能就是播放视频,在这里介绍一个简单的基于DirectShow的播放器的例子,是用MFC做的,今后有机会可以基于该播放器开发更复杂的播放器软件. 注:该例子取自于<D ...
- UE4学习心得:Scene Component蓝图的一个简单应用
Scene Component是蓝图类中一个不怎么常用的分类(特别是对于新手而言),主要是其实现的功能可以在Actor类中用相同的方法实现,使其作用显得有点多余. 笔者在使用过这个类之后发现其作用更相 ...
- JMS学习(四)-一个简单的聊天应用程序分析
一,介绍 本文介绍一个简单的聊天应用程序:生产者将消息发送到Topic上,然后由ActiveMQ将该消息Push给订阅了该Topic的消费者.示例程序来自于<JAVA 消息服务--第二版 Mar ...
- 《深度解析Tomcat》 第一章 一个简单的Web服务器
本章介绍Java Web服务器是如何运行的.从中可以知道Tomcat是如何工作的. 基于Java的Web服务器会使用java.net.Socket类和java.net.ServerSocket类这两个 ...
- Matlab高级教程_第二篇:一个简单的混编例子
1. 常用的混编是MATLAB和VS两个编辑器之间的混编方式. 2. 因为MATLAB的核是C型语言,因此常见的混编方式是MATLAB和C型语言的混编. 3. 这里介绍一个简单的MATLAB语言混编成 ...
- 用c#自己实现一个简单的JSON解析器
一.JSON格式介绍 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着很多优点.例如易读性更好,占用空间更 ...
随机推荐
- EF test
LibraryEntities db = new LibraryEntities(); private void btnSelect_Click(object sender, EventArgs e) ...
- Docker系列之入门
Docker基本介绍 一.什么是Docker 在docker的官方之什么是docker中提到了一句话:“当今各大组织或者团体的创新都源于软件(例如OA.ERP等),其实很多公司都是软件公司" ...
- mysql中int、bigint、smallint 和 tinyint的区别与长度
各种整形,总结留作参考. bigint 从 -2^63 (-9223372036854775808) 到 2^63-1 (9223372036854775807) 的整型数据(所有数字).存储大小为 ...
- " \t\r\n\f"是什么意思
空格字符 \t 制表符 \r 回车符 \n 换行符 \f 换页符
- xml方式实现aop编程
第一:引入jai文件 第二:引入aop名称空间 第三:配置aop
- Spring实战(中文4,5版) PDF含源码
Spring实战 读者评价 看了一半后在做评论,物流速度挺快,正版行货,只是运输过程有点印记,但是想必大家和你关注内容,spring 4必之3更加关注的是使用注解做开发,对于初学者还是很有用,但是不排 ...
- 自编码器----Autoencoder
一.自编码器:降维[无监督学习] PCA简介:[线性]原矩阵乘以过渡矩阵W得到新的矩阵,原矩阵和新矩阵是同样的东西,只是通过W换基. 自编码: 自动编码器是一种无监督的神经网络模型,它可以学习到输入数 ...
- 【剑指Offer】 24、二叉树中和为某一值的路径
题目描述: 输入一颗二叉树的根结点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.(注意: 在返回值的list中, ...
- router-link-active 与 router-link-exact-active 区别
我的github:swarz,欢迎给老弟我++星星 router-link-exact-active 是精确匹配规则,即只有当前点击router被匹配 router-link-active 默认是全包 ...
- IE下自定义错误页面不显示的原因
如果一个 404 页面的内容小于 512B,IE 会认为该 404 页面不够友好,在 IE 下将不会成功返回该 404 错误页面