Remember our last delegate type of parser, before starting this article, we strongly recommend that you review this parser definition
Public Delegate Maybe<tuple<t,string>>Parser<T> (string input)
Remember how hard it was for us to combine these parser? Now that we've converted parser to monad in a new way, we've learned how to convert generic and generic interfaces to Monad, and you can also convert delegates to Monad
First we implement a Toparser method, which is fairly simple and returns only one parser that does not consume any input string.
Public Static Parser<t>toparser ( this T value) {return input=>new just<tuple<t, string>>(tuple.create (value,input))}
Next we need a bind method that recalls the signature of the Bind method, remembering all the same Monad bind method signatures.
public static parser<b> bind<a,b> (this parser<a>a, Func<a,parser<b>>func) ()
Now we step into bind, first look at the return type Parser<b> Remember that parser<b> is a parameter that returns a function of type maybe<tuple<b,string>> with a string. So we need to return a lambda expression for this function
Public Static Parser<b>bind<a,b> ( This parser<a> A, func<a,parser<b>func>) {input = ={//... }}
This lambda needs to return maybe<tuple<b,string>> we can return parser<b> by calling Func, and then calling Parser<b> to return it:
Public Static Parser<b>bind<a,b> ( This parser<a>a, func<a,parser<b>>Func) { Return input=>{var bparser=func (??? ); return Bparser (??? );};}
We need a parameter a called Func, we can call a to get its return value and then take a from it:
Public StaticParser<b> bind<a,b> ( ThisParser<a>a, func<a,parser<b>>func) { returnInput=>{ varAmaybe=a (input);varAresult=amaybe asJust<tuple<a,string>>; //Short circuit If parse failsif(Aresult = =NULL)return NewNothing<tuple<b,string>>();varAvalue=aResult.Value.Item1;varBparser=func (avalue);returnBparser (???);}}
Note that we shorted out the parsing process, if there is a parser failure, this means that any parser combination will return nothing if one of the parsers cannot resolve its input.
Finally we need a string as the input to the Bparser, which can be obtained from the return result of parser a:
Public StaticParser<b> bind<a,b> ( ThisParser<a>a, func<a,parser<b>>func) { returnInput=>{ varAmaybe=a (input);varAresult=amaybe asJust<tuple<a,string>>; //Short circuit If parse failsif(Aresult = =NULL)return NewNothing<tuple<b,string>>();varAvalue=aResult.Value.Item1;varsstring=aResult.Value.Item2;varBparser=func (avalue);returnBparser (sstring);}}
We have created a Monad parser, in order to use LINQ syntax, we need to implement SelectMany,
Now we can implement our Hello World parser with just the following three lines of code.
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 ()));}
varHelloworldparser= fromHelloinch "Hello". Find () fromWorldinch " World". Find ()Select New(Hello=hello, world=World );varResult=helloworldparser ("HelloWorld"); Console.WriteLine (Result. Asstring (x=X.hello)); Console.WriteLine (Result. Asstring (x=x.world));//outputs//Hello// World
This implementation is full of beauty and hopefully you can start to understand how to create complex logic with monad, and if you want to learn more about Monad parser, the Nicholas Blumhardt implementation of project Sprache is for reference: https://github.com /sprache/sprache
Other Monad Resources reference:
Https://github.com/phenixyu/csharp-monad
Convert our parser into Monad