Last active
December 17, 2015 11:49
-
-
Save bleis-tift/5605388 to your computer and use it in GitHub Desktop.
C#でswitch文を再発明してしまった
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using LangExt; // ver1.x | |
namespace LangExt.Playground | |
{ | |
public interface IPattern<T, U> | |
{ | |
Option<_<U, T>> Match(T x); | |
} | |
public class Pat<T, U> : IPattern<T, U> | |
{ | |
readonly Func<T, Option<_<U, T>>> f; | |
public Pat(Func<T, Option<_<U, T>>> f) { this.f = f; } | |
public Option<_<U, T>> Match(T x) { return f(x); } | |
} | |
public static class Enumerable | |
{ | |
public static U Match<T, U>(this IEnumerable<T> self, Func<IEnumerable<T>, U> f) { return f(self); } | |
} | |
public static class SeqPattern | |
{ | |
public static IPattern<IEnumerable<T>, T> Any<T>() | |
{ | |
return new Pat<IEnumerable<T>, T>(t => t.Any() ? Option.Some(Tpl.Of(t.First(), t.Skip(1))) : Option.None); | |
} | |
public static IPattern<IEnumerable<T>, T> Eq<T>(T x) | |
{ | |
return new Pat<IEnumerable<T>, T>(t => t.Any() && t.First().Equals(x) ? Option.Some(Tpl.Of(t.First(), t.Skip(1))) : Option.None); | |
} | |
public static IPattern<IEnumerable<T>, IEnumerable<T>> Rest<T>() | |
{ | |
return new Pat<IEnumerable<T>, IEnumerable<T>>(xs => Option.Some(Tpl.Of(xs, xs))); | |
} | |
public static IPattern<IEnumerable<T>, T> Pred<T>(Func<T, bool> pred) | |
{ | |
return new Pat<IEnumerable<T>, T>(t => t.Any() && pred(t.First()) ? Option.Some(Tpl.Of(t.First(), t.Skip(1))) : Option.None); | |
} | |
} | |
public class SeqPattern<T, T1> | |
{ | |
private IPattern<IEnumerable<T>, T1> pat1; | |
public SeqPattern(IPattern<IEnumerable<T>, T1> pat1) | |
{ | |
this.pat1 = pat1; | |
} | |
public Func<IEnumerable<T>, U> Then<U>(Func<T1, U> f, Func<IEnumerable<T>, U> otherwise) | |
{ | |
return xs => | |
{ | |
var res = | |
from tpl1 in pat1.Match(xs) | |
select f(tpl1._1); | |
return res.Match(x => x, _ => otherwise(xs)); | |
}; | |
} | |
public Func<IEnumerable<T>, U> Then<U>(Func<T1, U> f) | |
{ | |
return Then(f, _ => { throw new Exception(); }); | |
} | |
} | |
public class SeqPattern<T, T1, T2> | |
{ | |
private IPattern<IEnumerable<T>, T1> pat1; | |
private IPattern<IEnumerable<T>, T2> pat2; | |
public SeqPattern(IPattern<IEnumerable<T>, T1> pat1, IPattern<IEnumerable<T>, T2> pat2) | |
{ | |
this.pat1 = pat1; | |
this.pat2 = pat2; | |
} | |
public Func<IEnumerable<T>, U> Then<U>(Func<T1, T2, U> f, Func<IEnumerable<T>, U> otherwise) | |
{ | |
return xs => | |
{ | |
var res = | |
from tpl1 in pat1.Match(xs) | |
from tpl2 in pat2.Match(tpl1._2) | |
select f(tpl1._1, tpl2._1); | |
return res.Match(x => x, _ => otherwise(xs)); | |
}; | |
} | |
public Func<IEnumerable<T>, U> Then<U>(Func<T1, T2, U> f) | |
{ | |
return Then(f, _ => { throw new Exception(); }); | |
} | |
} | |
public static partial class Pattern | |
{ | |
public static SeqPattern<T, U> ToSeqPattern<T, U>(this IPattern<IEnumerable<T>, U> self) | |
{ | |
return new SeqPattern<T, U>(self); | |
} | |
public static SeqPattern<T, T1, T2> And<T, T1, T2>(this IPattern<IEnumerable<T>, T1> self, IPattern<IEnumerable<T>, T2> nextPat) | |
{ | |
return new SeqPattern<T, T1, T2>(self, nextPat); | |
} | |
} | |
public class PatternFactory | |
{ | |
public class Seq<T> | |
{ | |
public IPattern<IEnumerable<T>, T> Any | |
{ | |
get { return SeqPattern.Any<T>(); } | |
} | |
public IPattern<IEnumerable<T>, T> Eq(T x) | |
{ | |
return SeqPattern.Eq(x); | |
} | |
public IPattern<IEnumerable<T>, IEnumerable<T>> Rest | |
{ | |
get { return SeqPattern.Rest<T>(); } | |
} | |
public IPattern<IEnumerable<T>, T> Pred(Func<T, bool> pred) | |
{ | |
return SeqPattern.Pred(pred); | |
} | |
} | |
} | |
partial class Pattern | |
{ | |
public static SeqPattern<T, T1> Seq<T, T1>(IPattern<IEnumerable<T>, T1> pat1) | |
{ | |
return new SeqPattern<T, T1>(pat1); | |
} | |
public static SeqPattern<T, T1, T2> Seq<T, T1, T2>(IPattern<IEnumerable<T>, T1> pat1, IPattern<IEnumerable<T>, T2> pat2) | |
{ | |
return new SeqPattern<T,T1,T2>(pat1, pat2); | |
} | |
} | |
public class Sample | |
{ | |
public static void Main() | |
{ | |
var _ = new PatternFactory.Seq<int>(); | |
var pat = _.Any.And(_.Rest); | |
var xs = new[] { 1, 2, 3, 4, 5 }; | |
pat.Then((hd, tl) => { Console.WriteLine("head:{0}, tail:{1}", hd, string.Join(", ", tl)); return 0; })(xs); | |
pat.Then((hd, tl) => { Console.WriteLine("head:{0}, tail:{1}", hd, string.Join(", ", tl)); return 0; })(new[] { 42 }); | |
try | |
{ | |
pat.Then((hd, tl) => { Console.WriteLine("head:{0}, tail:{1}", hd, string.Join(", ", tl)); return 0; })(new int[0]); | |
} | |
catch | |
{ | |
Console.WriteLine("oops!"); | |
} | |
var pat1 = _.Eq(10).ToSeqPattern(); | |
var pat2 = _.Pred(i => i % 2 == 0).ToSeqPattern(); | |
(new[] { 2, 3, 4 }).Match( | |
pat1.Then( | |
i => { Console.WriteLine("pat1"); return 0; }, | |
pat2.Then( | |
i => { Console.WriteLine("pat2"); return 0; }, | |
_.Rest.ToSeqPattern().Then( | |
i => { Console.WriteLine("pat3"); return 0; }, | |
pat1.Then<int>( | |
i => { throw new Exception(); }))))); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment