FunctionalToolKit
This file contains 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
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); | |
} |
This file contains 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
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)); | |
} |
This file contains 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
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; | |
} | |
} |
This file contains 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
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(); | |
} |
This file contains 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
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); | |
} | |
} |
This file contains 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
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