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

  • 相关阅读:
    php
    php数据排序---array_multisort
    IOS 线程描述
    IOS 进程描述
    IOS 强指针(strong)和弱指针(weak)
    IOS autosizing(设置控件的固定位置大小)
    IOS UIActivityIndicatorView动画
    IOS UIImageView的帧动画
    IOS Block动画
    IOS UIView动画(封装动画)
  • 原文地址:https://www.cnblogs.com/phenixyu/p/5621929.html
Copyright © 2011-2022 走看看