Last active
October 29, 2018 12:52
-
-
Save tonymorris/a8a1dfeb2fd8f69fba2036a6451a0c6d to your computer and use it in GitHub Desktop.
This file contains hidden or 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.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