using System; using System.Runtime.Serialization; namespace ZeroLevel.Services.Extensions { /// <summary> /// FP /// </summary> public static class FPCommon { /* * Func<int,int,int> add = (x,y) => x + y; * Func<int,Func<int,int>> curriedAdd = add.Curry(); * Func<int,int> inc = curriedAdd(1); */ /// <summary> /// Currying /// </summary> public static Func<A, Func<B, R>> Curry<A, B, R>(this Func<A, B, R> f) { return a => b => f(a, b); } /* * Func<int,int,int> add = (x,y) => x + y; * Func<int,int> inc = add.Partial(1); */ /// <summary> /// Partial currying /// </summary> public static Func<B, R> Partial<A, B, R>(this Func<A, B, R> f, A a) { return b => f(a, b); } /// <summary> /// PipeTo /// </summary> /* * Before * public IActionResult Get() {var someData = query.Where(x => x.IsActive).OrderBy(x => x.Id).ToArray();return Ok(someData);} * After * public IActionResult Get() => query.Where(x => x.IsActive).OrderBy(x => x.Id).ToArray().PipeTo(Ok); */ public static TResult PipeTo<TSource, TResult>(this TSource source, Func<TSource, TResult> func) => func(source); } public class Either<TL, TR> { [DataMember] private readonly bool _isLeft; [DataMember] private readonly TL _left; [DataMember] private readonly TR _right; public Either(TL left) { _left = left; _isLeft = true; } public Either(TR right) { _right = right; _isLeft = false; } /// <summary> /// Checks the type of the value held and invokes the matching handler function. /// </summary> /// <typeparam name="T">The return type of the handler functions.</typeparam> /// <param name="ofLeft">Handler for the Left type.</param> /// <param name="ofRight">Handler for the Right type.</param> /// <returns>The value returned by the invoked handler function.</returns> /// <exception cref="System.ArgumentNullException"> /// </exception> public T Match<T>(Func<TL, T> ofLeft, Func<TR, T> ofRight) { if (ofLeft == null) { throw new ArgumentNullException(nameof(ofLeft)); } if (ofRight == null) { throw new ArgumentNullException(nameof(ofRight)); } return _isLeft ? ofLeft(_left) : ofRight(_right); } /// <summary> /// Checks the type of the value held and invokes the matching handler function. /// </summary> /// <param name="ofLeft">Handler for the Left type.</param> /// <param name="ofRight">Handler for the Right type.</param> /// <exception cref="System.ArgumentNullException"> /// </exception> public void Match(Action<TL> ofLeft, Action<TR> ofRight) { if (ofLeft == null) { throw new ArgumentNullException(nameof(ofLeft)); } if (ofRight == null) { throw new ArgumentNullException(nameof(ofRight)); } if (_isLeft) { ofLeft(_left); } else { ofRight(_right); } } public TL LeftOrDefault() => Match(l => l, r => default(TL)); public TR RightOrDefault() => Match(l => default(TR), r => r); public Either<TR, TL> Swap() => Match(Right<TR, TL>, Left<TR, TL>); public Either<TL, T> Bind<T>(Func<TR, T> f) => BindMany(x => Right<TL, T>(f(x))); public Either<TL, T> BindMany<T>(Func<TR, Either<TL, T>> f) => Match(Left<TL, T>, f); public Either<TL, TResult> BindMany<T, TResult>(Func<TR, Either<TL, T>> f, Func<TR, T, TResult> selector) => BindMany(x => f(x).Bind(t => selector(_right, t))); public static implicit operator Either<TL, TR>(TL left) => new Either<TL, TR>(left); public static implicit operator Either<TL, TR>(TR right) => new Either<TL, TR>(right); public static Either<TLeft, TRight> Left<TLeft, TRight>(TLeft left) => new Either<TLeft, TRight>(left); public static Either<TLeft, TRight> Right<TLeft, TRight>(TRight right) => new Either<TLeft, TRight>(right); public static Either<Exception, T> Try<T>(Func<T> f) { try { return new Either<Exception, T>(f.Invoke()); } catch (Exception ex) { return new Either<Exception, T>(ex); } } } }