zoukankan      html  css  js  c++  java
  • 将我们的parser转换成Monad

         还记得我们上一篇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

  • 相关阅读:
    sp2010 升级sp2013 用户无法打开网站
    powerviot install in sharepoint 2013
    can not connect cube in performancce dashboard
    westrac server security configure user info
    添加报表服务在多服务器场
    sharepoint 2013 office web app 2013 文档在线浏览 IE11 浏览器不兼容解决方法
    delete job definition
    目前付款申请单内网打开慢的问题
    item style edit in sharepoint 2013
    Could not load file or assembly '$SharePoint.Project.AssemblyFullName$'
  • 原文地址:https://www.cnblogs.com/phenixyu/p/5621929.html
Copyright © 2011-2022 走看看