using System.Collections.Generic;
public delegate Maybe<(T Token, string Remainder)> Parser<T>(string input);
public static void Main()
var result = Parsers.FindHello("Hello World");
var justResult = result as Maybe<(string Token, string Remainder)>;
Console.Out.WriteLine($"justResult.Value.Token = {justResult.Value.Token}");
Console.Out.WriteLine($"justResult.Value.Remainder = {justResult.Value.Remainder}");
var result2 = Parsers.FindHello("Goodbye World");
Console.Out.WriteLine("result2 = {0}", result2.HasValue ? result2.Value.Remainder : "Nothing");
var helloParser = "Hello".Find();
var worldParser = "World".Find();
var result3 = helloParser("Hello World").AsString(s => s);
Console.Out.WriteLine("result3 = {0}", result3);
var result4 = worldParser("World Hello").AsString(s => s);
Console.Out.WriteLine("result4 = {0}", result4);
Parser<(string, string)> helloWorldParser = s =>
var helloResult = helloParser(s) as Maybe<(string, string)>;
if (helloResult == null) return Maybe<((string, string), string)>.Nothing;
var worldResult = worldParser(helloResult.Value.Item2) as Maybe<(string, string)>;
if (worldResult == null) return Maybe<((string, string), string)>.Nothing;
return Maybe<((string, string), string)>.Just(((helloResult.Value.Item1, worldResult.Value.Item1), worldResult.Value.Item2));
var result5 = helloWorldParser("HelloWorld").AsString(s => s.Item1 + " " + s.Item2);
Console.WriteLine(result5);
var p = from h in "Hello".Find()
select (Hello: h, World: w);
var result6 = p("HelloWorld");
Console.WriteLine(result6.AsString(t => t.Hello));
Console.WriteLine(result6.AsString(t => t.World));
public static class ParserExtensions
public static Parser<T> ToParser<T>(this T a) => s => Maybe<(T, string)>.Just((a, s));
public static Parser<B> SelectMany<A, B>(this Parser<A> a, Func<A, Parser<B>> func) => s =>
var aResult = aMaybe as Maybe<(A Token, string Remainder)>;
if (aResult == null) return Maybe<(B, string)>.Nothing;
var aToken = aResult.Value.Token;
var aRemainder = aResult.Value.Remainder;
var bParser = func(aToken);
return bParser(aRemainder);
public static Parser<C> SelectMany<A, B, C>(this Parser<A> a, Func<A, Parser<B>> func, Func<A, B, C> selector) =>
a.SelectMany(x => func(x).SelectMany(y => selector(x, y).ToParser()));
public static class Parsers
public static Maybe<(string Token, string Remainder)> FindHello(string input)
return input.StartsWith("Hello")
? Maybe<(string, string)>.Just(("Hello", input.Skip("Hello".Length).AsString()))
: Maybe<(string, string)>.Nothing;
public static string AsString(this IEnumerable<char> chars) => new string(chars.ToArray());
public static Parser<string> Find(this string stringToFind)
return s => s.StartsWith(stringToFind)
? Maybe<(string, string)>.Just((stringToFind, s.Skip(stringToFind.Length).AsString()))
: Maybe<(string, string)>.Nothing;
public static string AsString<T>(this Maybe<(T Token, string Remainder)> parseResult, Func<T, string> unwrap)
return (parseResult != null)
? unwrap(parseResult.Value.Token)
public bool HasValue { get; private set;} = false;
public T Value {get; private set;} = default(T);
public static Maybe<T> Just(T value) => new Maybe<T> {Value = value, HasValue = true};
public static Maybe<T> Nothing => new Maybe<T>();
public static class MaybeExtension
public static Maybe<A> ToMaybe<A>(this A a) => Maybe<A>.Just(a);
public static Maybe<B> SelectMany<A, B>(this Maybe<A> a, Func<A, Maybe<B>> func) => a.HasValue ? func(a.Value) : Maybe<B>.Nothing;
public static Maybe<C> SelectMany<A, B, C>(this Maybe<A> a, Func<A, Maybe<B>> func, Func<A, B, C> selector) =>
a.SelectMany(x => func(x).SelectMany(y => selector(x, y).ToMaybe()));
public static Maybe<int> Div(this int numerator, int denominator)
: Maybe<int>.Just(numerator / denominator);