Skip to content

Instantly share code, notes, and snippets.

@gregberns
Forked from tonymorris/dearcsharp.cs
Created October 29, 2018 12:52
Show Gist options
  • Save gregberns/d5f36e6aed2e05eca69e77164033cd0c to your computer and use it in GitHub Desktop.
Save gregberns/d5f36e6aed2e05eca69e77164033cd0c to your computer and use it in GitHub Desktop.
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