Skip to content

Instantly share code, notes, and snippets.

@cameronpresley
Created June 8, 2018 19:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cameronpresley/5acc651ade335a323ca98289f7ed51f5 to your computer and use it in GitHub Desktop.
Save cameronpresley/5acc651ade335a323ca98289f7ed51f5 to your computer and use it in GitHub Desktop.
FunctionalToolKit
public static class FunctionExtensions
{
public static Func<T2> Apply<T1, T2>(this Func<T1, T2> func, T1 input) => () => func(input);
public static Func<T2, T3> Apply<T1, T2, T3>(this Func<T1, T2, T3> func, T1 input) => x => func(input, x);
public static Func<T2, T3, T4> Apply<T1, T2, T3, T4>(this Func<T1, T2, T3, T4> func, T1 input) =>
(a, b) => func(input, a, b);
public static Action Apply<T1>(this Action<T1> action, T1 input) => () => action(input);
public static Action<T2> Apply<T1, T2>(this Action<T1, T2> action, T1 input) => a => action(input, a);
public static Action<T2, T3> Apply<T1, T2, T3>(this Action<T1, T2, T3> action, T1 input) =>
(a, b) => action(input, a, b);
}
public static class FunctionHelpers
{
public static T Identity<T>(T input) => input;
public static void Nothing<T>(T input) { }
public static Func<T1, T3> Compose<T1, T2, T3>(Func<T1, T2> a, Func<T2, T3> b) => c => b(a(c));
}
public static class GenericExtensions
{
public static U Map<T, U>(this T input, Func<T, U> mapper) => mapper(input);
public static T Do<T>(this T input, Action<T> action)
{
action(input);
return input;
}
}
public interface IOption<out T>
{
IOption<U> Map<U>(Func<T, U> mapper);
IOption<U> Bind<U>(Func<T, IOption<U>> bind);
U Match<U>(Func<U> ifNone, Func<T, U> ifSome);
void Do(Action ifNone, Action<T> ifSome);
}
public static class Option
{
public static IOption<T> Some<T>(T value) => new Some<T>(value);
public static IOption<T> No<T>() => new None<T>();
public static IOption<T> Wrap<T>(Func<T> func)
{
try { return Some(func()); }
catch { return No<T>(); }
}
public static IOption<T> Wrap<T>(T value) => value == null ? No<T>() : Some(value);
public static IOption<TResult> Apply<T1, T2, TResult>(Func<T1, T2, TResult> func, IOption<T1> a, IOption<T2> b)
{
return a is Some<T1> aSome && b is Some<T2> bSome
? Some(func(aSome._value, bSome._value))
: No<TResult>();
}
public static IOption<TResult> Apply<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, IOption<T1> a,
IOption<T2> b, IOption<T3> c)
{
return a is Some<T1> aSome && b is Some<T2> bSome && c is Some<T3> cSome
? Some(func(aSome._value, bSome._value, cSome._value))
: No<TResult>();
}
}
internal struct Some<T> : IOption<T>
{
internal readonly T _value;
public Some(T value) => _value = value;
public IOption<U> Map<U>(Func<T, U> mapper) => new Some<U>(mapper(_value));
public IOption<U> Bind<U>(Func<T, IOption<U>> bind) => bind(_value);
public U Match<U>(Func<U> ifNone, Func<T, U> ifSome) => ifSome(_value);
public void Do(Action ifNone, Action<T> ifSome) => ifSome(_value);
}
internal struct None<T> : IOption<T>
{
public IOption<U> Map<U>(Func<T, U> mapper) => new None<U>();
public IOption<U> Bind<U>(Func<T, IOption<U>> bind) => new None<U>();
public U Match<U>(Func<U> ifNone, Func<T, U> ifSome) => ifNone();
public void Do(Action ifNone, Action<T> ifSome) => ifNone();
}
public static class PredicateMonoid
{
public static Func<T, bool> AndCombine<T>(params Func<T, bool>[] preds)
{
Func<T, bool> id = _ => true;
Func<Func<T, bool>, Func<T, bool>, Func<T, bool>> and = (a, b) => c => a(c) && b(c);
return preds.Aggregate(id, and);
}
public static Func<T, bool> OrCombine<T>(params Func<T, bool>[] preds)
{
Func<T, bool> id = _ => false;
Func<Func<T, bool>, Func<T, bool>, Func<T, bool>> or = (a, b) => c => a(c) || b(c);
return preds.Aggregate(id, or);
}
}
public interface IResult<TFailure, TSuccess>
{
IResult<TFailure, USuccess> Map<USuccess>(Func<TSuccess, USuccess> mapper);
IResult<TFailure, USuccess> Bind<USuccess>(Func<TSuccess, IResult<TFailure, USuccess>> binder);
IResult<UFailure, USuccess> BiMap<UFailure, USuccess>(Func<TFailure, UFailure> ifFailure,
Func<TSuccess, USuccess> ifSuccess);
T Match<T>(Func<TFailure, T> ifFailure, Func<TSuccess, T> ifSuccess);
IResult<TFailure, TSuccess> Do(Action<TFailure> onFailure, Action<TSuccess> onSuccess);
}
internal struct Success<TFailure, TSuccess> : IResult<TFailure, TSuccess>
{
internal readonly TSuccess _value;
public Success(TSuccess value) => _value = value;
public IResult<TFailure, USuccess> Map<USuccess>(Func<TSuccess, USuccess> mapper)
=> new Success<TFailure, USuccess>(mapper(_value));
public IResult<TFailure, USuccess> Bind<USuccess>(Func<TSuccess, IResult<TFailure, USuccess>> binder)
=> binder(_value);
public IResult<UFailure, USuccess> BiMap<UFailure, USuccess>(Func<TFailure, UFailure> ifFailure, Func<TSuccess, USuccess> ifSuccess)
=> new Success<UFailure, USuccess>(ifSuccess(_value));
public T Match<T>(Func<TFailure, T> ifFailure, Func<TSuccess, T> ifSuccess) => ifSuccess(_value);
public IResult<TFailure, TSuccess> Do(Action<TFailure> onFailure, Action<TSuccess> onSuccess)
{
onSuccess(_value);
return this;
}
}
internal struct Failure<TFailure, TSuccess> : IResult<TFailure, TSuccess>
{
private readonly TFailure _value;
public Failure(TFailure value) => _value = value;
public IResult<TFailure, USuccess> Map<USuccess>(Func<TSuccess, USuccess> mapper)
=> new Failure<TFailure, USuccess>(_value);
public IResult<TFailure, USuccess> Bind<USuccess>(Func<TSuccess, IResult<TFailure, USuccess>> binder)
=> new Failure<TFailure, USuccess>(_value);
public IResult<UFailure, USuccess> BiMap<UFailure, USuccess>(Func<TFailure, UFailure> ifFailure,
Func<TSuccess, USuccess> ifSuccess)
=> _value.Map(ifFailure).Map(x => new Failure<UFailure, USuccess>(x));
public T Match<T>(Func<TFailure, T> ifFailure, Func<TSuccess, T> ifSuccess)
=> ifFailure(_value);
public IResult<TFailure, TSuccess> Do(Action<TFailure> onFailure, Action<TSuccess> onSuccess)
{
onFailure(_value);
return this;
}
}
public static class Result
{
public static IResult<TFailure, TSuccess> Success<TFailure, TSuccess>(TSuccess value) => new Success<TFailure, TSuccess>(value);
public static IResult<TFailure, TSuccess> Failure<TFailure, TSuccess>(TFailure value) => new Failure<TFailure, TSuccess>(value);
public static IResult<Exception, TSuccess> Wrap<TSuccess>(Func<TSuccess> func)
{
try {return func().Map(Success<Exception, TSuccess>);}
catch (Exception ex) {return ex.Map(Failure<Exception, TSuccess>);}
}
public static IResult<List<TFailure>, TSuccess> Apply<TFailure, TSuccess, T1, T2>(Func<T1, T2, TSuccess> func, IResult<TFailure, T1> a, IResult<TFailure, T2> b)
{
List<TFailure> failures = new List<TFailure>();
a.Do(failures.Add, _ => { });
b.Do(failures.Add, _=>{});
return failures.Any()
? Failure<List<TFailure>, TSuccess>(failures)
: func(((Success<TFailure, T1>)a)._value, ((Success<TFailure, T2>)b)._value)
.Map(Success<List<TFailure>, TSuccess>);
}
public static IResult<List<TFailure>, TSuccess> Apply<TFailure, TSuccess, T1, T2, T3>(Func<T1, T2, T3, TSuccess> func, IResult<TFailure, T1> a, IResult<TFailure, T2> b, IResult<TFailure, T3> c)
{
List<TFailure> failures = new List<TFailure>();
a.Do(failures.Add, _ => { });
b.Do(failures.Add, _ => { });
c.Do(failures.Add, _=>{});
return failures.Any()
? Failure<List<TFailure>, TSuccess>(failures)
: func(((Success<TFailure, T1>)a)._value, ((Success<TFailure, T2>)b)._value, ((Success<TFailure, T3>)c)._value)
.Map(Success<List<TFailure>, TSuccess>);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment