| using System; | |
| using System.Linq; | |
| using System.Collections.Generic; | |
| namespace DearCSharpYouLose { | |
| public static class FuncExtension { | |
| public static Func<A, C> Select<A, B, C>(this Func<A, B> f, Func<B, C> g) { | |
| return a => g(f(a)); | |
| } | |
| public static Func<C, B> SelectMany<A, B, C>(this Func<C, A> f, Func<A, Func<C, B>> g) { | |
| return a => g(f(a))(a); | |
| } | |
| public static Func<C, D> SelectMany<A, B, C, D>(this Func<C, A> f, Func<A, Func<C, B>> p, Func<A, B, D> k) { | |
| return SelectMany<A, D, C>(f, b => Select<C, B, D>(p(b), x => k(b, x))); | |
| } | |
| } | |
| public struct Option<A> { | |
| private readonly bool ne; | |
| private readonly A a; | |
| private Option(bool e, A a) { | |
| this.ne = !e; | |
| this.a = a; | |
| } | |
| public static Option<A> Empty { | |
| get { | |
| return new Option<A>(true, default(A)); | |
| } | |
| } | |
| public static Option<A> Some(A t) { | |
| return new Option<A>(false, t); | |
| } | |
| public X Fold<X>(Func<A, X> some, Func<X> empty) { | |
| return ne ? empty() : some(a); | |
| } | |
| } | |
| public static class OptionExtension { | |
| public static Option<B> Select<A, B>(this Option<A> k, Func<A, B> f) { | |
| return k.Fold<Option<B>>(a => Option<B>.Some(f(a)), () => Option<B>.Empty); | |
| } | |
| public static Option<B> SelectMany<A, B>(this Option<A> k, Func<A, Option<B>> f) { | |
| return k.Fold(f, () => Option<B>.Empty); | |
| } | |
| public static Option<C> SelectMany<A, B, C>(this Option<A> k, Func<A, Option<B>> p, Func<A, B, C> f) { | |
| return SelectMany(k, a => Select(p(a), b => f(a, b))); | |
| } | |
| } | |
| public struct State<S, A> { | |
| private readonly Func<S, Tuple<S, A>> run; | |
| private State(Func<S, Tuple<S, A>> run) { | |
| this.run = run; | |
| } | |
| public static State<S, A> state(Func<S, Tuple<S, A>> run) { | |
| return new State<S, A>(run); | |
| } | |
| public Func<S, Tuple<S, A>> Run { | |
| get { | |
| return run; | |
| } | |
| } | |
| } | |
| public static class StateExtension { | |
| public static State<S, B> Select<S, A, B>(this State<S, A> k, Func<A, B> f) { | |
| return State<S, B>.state(s => { | |
| var r = k.Run(s); | |
| return Tuple.Create(r.Item1, f(r.Item2)); | |
| }); | |
| } | |
| public static State<S, B> SelectMany<S, A, B>(this State<S, A> k, Func<A, State<S, B>> f) { | |
| return State<S, B>.state(s => { | |
| var r = k.Run(s); | |
| return f(r.Item2).Run(r.Item1); | |
| }); | |
| } | |
| public static State<S, C> SelectMany<S, A, B, C>(this State<S, A> k, Func<A, State<S, B>> p, Func<A, B, C> f) { | |
| return default(State<S, C>); | |
| } | |
| } | |
| // Dear C# please factor out all this code repetition. | |
| // If it is apologised away, please let me know, and I'll keep coming up with more examples. | |
| // I will do this until the apologies stop. | |
| public static class DRY_LOL { | |
| // existing data type, extended with SelectMany above | |
| public static Func<T, D> FuncThrice<A, B, C, D, T>(Func<A, B, C, D> f, Func<T, A> ta, Func<T, B> tb, Func<T, C> tc) { | |
| return | |
| from a in ta | |
| from b in tb | |
| from c in tc | |
| select f(a, b, c); | |
| } | |
| // existing data type, already extended with SelectMany | |
| public static IEnumerable<D> IEnumerableThrice<A, B, C, D>(Func<A, B, C, D> f, IEnumerable<A> ta, IEnumerable<B> tb, IEnumerable<C> tc) { | |
| return | |
| from a in ta | |
| from b in tb | |
| from c in tc | |
| select f(a, b, c); | |
| } | |
| // existing data type, already extended with SelectMany | |
| public static IQueryable<D> IQueryableThrice<A, B, C, D>(Func<A, B, C, D> f, IQueryable<A> ta, IQueryable<B> tb, IQueryable<C> tc) { | |
| return | |
| from a in ta | |
| from b in tb | |
| from c in tc | |
| select f(a, b, c); | |
| } | |
| // custom data type, extended with SelectMany | |
| public static Option<D> OptionThrice<A, B, C, D>(Func<A, B, C, D> f, Option<A> ta, Option<B> tb, Option<C> tc) { | |
| return | |
| from a in ta | |
| from b in tb | |
| from c in tc | |
| select f(a, b, c); | |
| } | |
| // custom data type, extended with SelectMany | |
| public static State<S, D> FuncThrice<A, B, C, D, S>(Func<A, B, C, D> f, State<S, A> ta, State<S, B> tb, State<S, C> tc) { | |
| return | |
| from a in ta | |
| from b in tb | |
| from c in tc | |
| select f(a, b, c); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment