我们已经学习了怎样创建一个简单的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的更多相关文章

  1. 安全小测试:介绍一个简单web安全知识测试的网站

    https://websecurity.firebaseapp.com/ 一次测试一共7道题,最后有答案,可以反复做,每次随机抽题

  2. 自己动手实现一个简单的JSON解析器

    1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...

  3. Web开发之tomcat配置及使用(环境变量设置及测试,一个简单的web应用实例)

    Tomcat的配置及测试: 第一步:下载tomcat,然后解压到任意盘符 第二步:配置系统环境变量 tomcat解压到的D盘 (路径为: D:\tomcat), 配置环境变量: 启动tomcat需要两 ...

  4. 一个简单的基于 DirectShow 的播放器 1(封装类)

    DirectShow最主要的功能就是播放视频,在这里介绍一个简单的基于DirectShow的播放器的例子,是用MFC做的,今后有机会可以基于该播放器开发更复杂的播放器软件. 注:该例子取自于<D ...

  5. UE4学习心得:Scene Component蓝图的一个简单应用

    Scene Component是蓝图类中一个不怎么常用的分类(特别是对于新手而言),主要是其实现的功能可以在Actor类中用相同的方法实现,使其作用显得有点多余. 笔者在使用过这个类之后发现其作用更相 ...

  6. JMS学习(四)-一个简单的聊天应用程序分析

    一,介绍 本文介绍一个简单的聊天应用程序:生产者将消息发送到Topic上,然后由ActiveMQ将该消息Push给订阅了该Topic的消费者.示例程序来自于<JAVA 消息服务--第二版 Mar ...

  7. 《深度解析Tomcat》 第一章 一个简单的Web服务器

    本章介绍Java Web服务器是如何运行的.从中可以知道Tomcat是如何工作的. 基于Java的Web服务器会使用java.net.Socket类和java.net.ServerSocket类这两个 ...

  8. Matlab高级教程_第二篇:一个简单的混编例子

    1. 常用的混编是MATLAB和VS两个编辑器之间的混编方式. 2. 因为MATLAB的核是C型语言,因此常见的混编方式是MATLAB和C型语言的混编. 3. 这里介绍一个简单的MATLAB语言混编成 ...

  9. 用c#自己实现一个简单的JSON解析器

    一.JSON格式介绍 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着很多优点.例如易读性更好,占用空间更 ...

随机推荐

  1. 【sqli-labs】 less26a GET- Blind based -All you SPACES and COMMENTS belong to us -String-single quotes-Parenthesis(GET型基于盲注的去除了空格和注释的单引号括号注入)

    这个和less26差不多,空格还是用%a0代替,26过了这个也就简单了 ;%00 可以代替注释,尝试一下 order by 3 http://192.168.136.128/sqli-labs-mas ...

  2. 【剑指Offer】31、从1到n整数中1出现的次数

      题目描述:   求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他 ...

  3. 多叉树结构的数据,parent表示法转成children表示法

    最近碰到的问题,有个数组,数组元素是对象,该对象的结构就如树的parent表示法的节点一样.形象点讲就是该数组存放了树的所有“叶子节点”,并且叶子节点内存有父节点,一直到根节点为止,就如存了一条从叶子 ...

  4. Python之scrapy linkextractors使用错误

    1.环境及版本 python3.7.1+scrapy1.5.1 2.问题及错误代码详情 优先贴上问题代码,如下: import scrapy from scrapy.linkextractors im ...

  5. Ubuntu 14.04远程登录服务器

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51285545 本文讲述在Ubuntu ...

  6. WinForm 登录窗体 + 单实例运行

    关于怎么在winform里增加登录窗体或者如何让winform程序单实例运行网上都很多例子. 然而两者结合起来呢? //Program.cs static class Program { public ...

  7. HDU - 1243 - 反恐训练营

    先上题目: 反恐训练营 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...

  8. Timus - 1213 - Cockroaches!

    先上题目: 1213. Cockroaches! Time limit: 1.0 secondMemory limit: 64 MB It's well-known that the most ten ...

  9. 【ACM】hdu_zs2_1003_Problem C_201308031012

    Problem C Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)Total Subm ...

  10. 教你高速高效接入SDK——Unity统一接入渠道SDK(Android篇)

    U8SDK的设计之初,就是为了可以支持各种游戏引擎开发的游戏,而不不过Android的原生平台.眼下一大半的手游,都是採用Unity3D和Cocos2dx开发,那么这里,我们就先来一步步给大家演示,用 ...