Skip to content

Instantly share code, notes, and snippets.

@bleis-tift
Last active December 17, 2015 11:49
Show Gist options
  • Save bleis-tift/5605388 to your computer and use it in GitHub Desktop.
Save bleis-tift/5605388 to your computer and use it in GitHub Desktop.
C#でswitch文を再発明してしまった
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