public TryAsync <A> Plus(TryAsync <A> ma, TryAsync <A> mb) => async() => { // Run in parallel var resA = ma.Try(); var resB = mb.Try(); var tasks = Set <OrdTask <Result <A> >, Task <Result <A> > >(resA, resB); while (tasks.Count > 0) { // Return first one that completes var completed = await Task.WhenAny(tasks).ConfigureAwait(false); if (!completed.IsFaulted && !completed.Result.IsFaulted) { return(completed.Result); } tasks = tasks.Remove(completed); } if (!resA.IsFaulted) { return(resA.Result); } if (!resB.IsFaulted) { return(resB.Result); } return(new Result <A>(new AggregateException(resA.Exception, resB.Exception))); };
public TryAsync <B> Action(TryAsync <A> fa, TryAsync <B> fb) => async() => { var a = fa.Try(); var b = fb.Try(); await Task.WhenAll(a, b); if (a.IsFaulted) { return(new Result <B>(a.Exception)); } if (b.IsFaulted) { return(new Result <B>(b.Exception)); } var ra = await a; if (ra.IsFaulted) { return(new Result <B>(ra.Exception)); } var rb = await b; if (rb.IsFaulted) { return(new Result <B>(rb.Exception)); } return(new Result <B>(rb.Value)); };
public static TryOptionAsync <TryAsync <B> > Traverse <A, B>(this TryAsync <TryOptionAsync <A> > ma, Func <A, B> f) { return(ToTry(() => Go(ma, f))); async Task <OptionalResult <TryAsync <B> > > Go(TryAsync <TryOptionAsync <A> > ma, Func <A, B> f) { var ra = await ma.Try().ConfigureAwait(false); if (ra.IsFaulted) { return(new OptionalResult <TryAsync <B> >(TryAsync <B>(ra.Exception))); } var rb = await ra.Value.Try().ConfigureAwait(false); if (rb.IsFaulted) { return(new OptionalResult <TryAsync <B> >(rb.Exception)); } if (rb.IsNone) { return(OptionalResult <TryAsync <B> > .None); } return(new OptionalResult <TryAsync <B> >(TryAsync <B>(f(rb.Value.Value)))); } }
public TryAsync <A> Plus(TryAsync <A> ma, TryAsync <A> mb) => async() => { // Run in parallel var resA = ma.Try(); var resB = mb.Try(); var tasks = Set <OrdTask <Result <A> >, Task <Result <A> > >(resA, resB); while (tasks.Count > 0) { // Return first one that completes var completed = await Task.WhenAny(tasks); if (!completed.IsFaulted && !completed.Result.IsFaulted) { return(completed.Result); } tasks = tasks.Remove(completed); } if (!resA.IsFaulted) { return(resA.Result); } if (!resB.IsFaulted) { return(resB.Result); } throw new BottomException(); };
/// <summary> /// Invoke a delegate if the Try returns a value successfully /// </summary> /// <param name="Succ">Delegate to invoke if successful</param> public static async Task <Unit> IfSucc <A>(this TryAsync <A> self, Action <A> Succ) { if (isnull(self)) { throw new ArgumentNullException(nameof(self)); } if (isnull(Succ)) { throw new ArgumentNullException(nameof(Succ)); } try { var res = await self.Try(); if (!res.IsFaulted) { Succ(res.Value); } return(unit); } catch (Exception e) { TryConfig.ErrorLogger(e); return(unit); } }
public static async Task <A> IfFail <A>(this TryAsync <A> self, Func <Exception, A> Fail) { if (isnull(self)) { throw new ArgumentNullException(nameof(self)); } if (isnull(Fail)) { throw new ArgumentNullException(nameof(Fail)); } try { var res = await self.Try(); if (res.IsFaulted) { return(Fail(res.Exception)); } else { return(res.Value); } } catch (Exception e) { TryConfig.ErrorLogger(e); return(Fail(e)); } }
public static TryAsync <R> BiBind <A, R>(this TryAsync <A> self, Func <A, TryAsync <R> > Succ, Func <Exception, TryAsync <R> > Fail) => Memo <R>(async() => { var res = await self.Try(); return(res.IsFaulted ? await Fail(res.Exception).Try() : await Succ(res.Value).Try()); });
public static TryAsync <B> BiMap <A, B>(this TryAsync <A> self, Func <A, Task <B> > Succ, Func <Exception, Task <B> > Fail) => Memo <B>(async() => { var res = await self.Try(); return(res.IsFaulted ? await Fail(res.Exception) : await Succ(res.Value)); });
public static EitherAsync <L, TryAsync <B> > Traverse <L, A, B>(this TryAsync <EitherAsync <L, A> > ma, Func <A, B> f) { return(new EitherAsync <L, TryAsync <B> >(Go(ma, f))); async Task <EitherData <L, TryAsync <B> > > Go(TryAsync <EitherAsync <L, A> > ma, Func <A, B> f) { var result = await ma.Try().ConfigureAwait(false); if (result.IsBottom) { return(EitherData <L, TryAsync <B> > .Bottom); } if (result.IsFaulted) { return(EitherData.Right <L, TryAsync <B> >(TryAsyncFail <B>(result.Exception))); } var db = await result.Value.Data.ConfigureAwait(false); if (db.State == EitherStatus.IsBottom) { return(EitherData <L, TryAsync <B> > .Bottom); } if (db.State == EitherStatus.IsLeft) { return(EitherData.Left <L, TryAsync <B> >(db.Left)); } return(EitherData.Right <L, TryAsync <B> >(TryAsync <B>(f(db.Right)))); } }
public TryAsync <B> Apply(TryAsync <Func <A, B> > fab, TryAsync <A> fa) => async() => { var f = fab.Try(); var a = fa.Try(); await Task.WhenAll(f, a); if (f.IsFaulted) { return(new Result <B>(f.Exception)); } if (a.IsFaulted) { return(new Result <B>(a.Exception)); } var rf = await f; if (rf.IsFaulted) { return(new Result <B>(rf.Exception)); } var ra = await a; if (ra.IsFaulted) { return(new Result <B>(ra.Exception)); } return(new Result <B>(rf.Value(ra.Value))); };
public async Task <int> GetHashCodeAsync(TryAsync <A> x) { var dx = await x.Try().ConfigureAwait(false); return(dx.IsSuccess ? await default(HashA).GetHashCodeAsync(dx.Value).ConfigureAwait(false) : 0); }
/// <summary> /// Impure iteration of the bound value in the structure /// </summary> /// <returns> /// Returns the original unmodified structure /// </returns> public static TryAsync <A> Do <A>(this TryAsync <A> ma, Action <A> f) => new TryAsync <A>(async() => { var r = await ma.Try(); if (!r.IsFaulted) { f(r.Value); } return(r); });
/// <summary> /// Performs the given action if the operation results in a failed state /// </summary> /// <param name="t">Current operation</param> /// <param name="ifFail">Action to execute with the exception that caused the failure</param> /// <typeparam name="T"></typeparam> /// <returns></returns> public static TryAsync <T> DoIfFail <T>(this TryAsync <T> t, Action <Exception> ifFail) => async() => { var optionResult = await t.Try(); if (optionResult.IsFaulted) { optionResult.IfFail(ifFail); } return(optionResult); };
public static TryAsync <A> Filter <A>(this TryAsync <A> self, Func <A, Task <bool> > pred) => Memo(async() => { var res = await self.Try(); if (res.IsFaulted) { return(res); } return(await pred(res.Value) ? res : raise <A>(new BottomException())); });
public static TryAsync <A> BiFilter <A>(this TryAsync <A> self, Func <A, Task <bool> > Succ, Func <Exception, Task <bool> > Fail) => Memo <A>(async() => { var res = await self.Try(); return(res.IsFaulted ? await Fail(res.Exception) ? res.Value : raise <A>(new BottomException()) : await Succ(res.Value) ? res.Value : raise <A>(new BottomException())); });
public TryAsync <A> Plus(TryAsync <A> ma, TryAsync <A> mb) => async() => { var a = await ma.Try(); if (a.IsSuccess) { return(a); } var b = await mb.Try(); return(b.IsSuccess ? b : new Result <A>(new AggregateException(a.Exception, b.Exception))); };
public static async ValueTask <TryAsync <B> > Traverse <A, B>(this TryAsync <ValueTask <A> > ma, Func <A, B> f) { var da = await ma.Try().ConfigureAwait(false); if (da.IsBottom) { throw new BottomException(); } if (da.IsFaulted) { return(TryAsyncFail <B>(da.Exception)); } var a = await da.Value.ConfigureAwait(false); return(TryAsyncSucc(f(a))); }
/// <summary> /// Memoize the computation so that it's only run once /// </summary> public static TryAsync <A> Memo <A>(this TryAsync <A> ma) { bool run = false; Result <A> result = new Result <A>(); return(new TryAsync <A>(async() => { if (run) { return result; } result = await ma.Try(); run = true; return result; })); }
/// <summary> /// Memoize the computation so that it's only run once /// </summary> public static TryAsync <A> Memo <A>(this TryAsync <A> ma) { bool run = false; var result = Result <A> .Bottom.AsTask(); return(new TryAsync <A>(() => { if (run) { return result; } result = ma.Try(); run = true; return result; })); }
public async Task <int> CompareAsync(TryAsync <A> x, TryAsync <A> y) { var dx = await x.Try().ConfigureAwait(false); var dy = await y.Try().ConfigureAwait(false); if (dx.IsBottom && dy.IsBottom) { return(0); } if (dx.IsFaulted && dy.IsFaulted) { return(0); } if (dx.IsSuccess && dy.IsSuccess) { return(await default(OrdA).CompareAsync(dx.Value, dy.Value).ConfigureAwait(false)); } if (dx.IsBottom && !dy.IsBottom) { return(-1); } if (!dx.IsBottom && dy.IsBottom) { return(1); } if (dx.IsFaulted && !dy.IsFaulted) { return(-1); } if (!dx.IsFaulted && dy.IsFaulted) { return(1); } if (dx.IsSuccess && !dy.IsSuccess) { return(-1); } if (!dx.IsSuccess && dy.IsSuccess) { return(1); } return(0); }
public static async Task <R> Match <A, R>(this TryAsync <A> self, Func <A, Task <R> > Succ, R Fail) { if (isnull(Succ)) { throw new ArgumentNullException(nameof(Succ)); } if (isnull(Fail)) { throw new ArgumentNullException(nameof(Fail)); } var res = await self.Try(); return(res.IsFaulted ? Fail : await Succ(res.Value)); }
public static async Task <A> IfFailThrow <A>(this TryAsync <A> self) { try { var res = await self.Try(); if (res.IsFaulted) { throw new InnerException(res.Exception); } return(res.Value); } catch (Exception e) { TryConfig.ErrorLogger(e); throw; } }
public static async Task <TryAsync <B> > Traverse <A, B>(this TryAsync <Task <A> > ma, Func <A, B> f) { var da = await ma.Try(); if (da.IsBottom) { throw new BottomException(); } if (da.IsFaulted) { return(TryAsyncFail <B>(da.Exception)); } var a = await da.Value; if (da.Value.IsFaulted) { ExceptionDispatchInfo.Capture(da.Value.Exception.InnerException).Throw(); } return(TryAsyncSucc(f(a))); }
public async Task <B> MatchAsync <B>(TryAsync <A> opt, Func <A, B> Some, Func <Task <B> > NoneAsync) { try { var res = await opt.Try().ConfigureAwait(false); if (res.IsFaulted) { return(Check.NullReturn(await NoneAsync().ConfigureAwait(false))); } else { return(Check.NullReturn(Some(res.Value))); } } catch { return(Check.NullReturn(await NoneAsync().ConfigureAwait(false))); } }
public async Task <B> MatchUnsafe <B>(TryAsync <A> opt, Func <A, B> Some, Func <B> None) { try { var res = await opt.Try().ConfigureAwait(false); if (res.IsFaulted) { return(None()); } else { return(Some(res.Value)); } } catch { return(None()); } }
public async Task <B> MatchUnsafeAsync <B>(TryAsync <A> opt, Func <A, Task <B> > SomeAsync, Func <Task <B> > NoneAsync) { try { var res = await opt.Try().ConfigureAwait(false); if (res.IsFaulted) { return(await NoneAsync().ConfigureAwait(false)); } else { return(await SomeAsync(res.Value).ConfigureAwait(false)); } } catch { return(await NoneAsync().ConfigureAwait(false)); } }
public async Task <B> Match <B>(TryAsync <A> opt, Func <A, B> Some, Func <B> None) { try { var res = await opt.Try(); if (res.IsFaulted) { return(Check.NullReturn(None())); } else { return(Check.NullReturn(Some(res.Value))); } } catch { return(Check.NullReturn(None())); } }
public async Task <B> MatchAsync <B>(TryAsync <A> opt, Func <A, Task <B> > SomeAsync, Func <Task <B> > NoneAsync) { try { var res = await opt.Try(); if (res.IsFaulted) { return(Check.NullReturn(await NoneAsync())); } else { return(Check.NullReturn(await SomeAsync(res.Value))); } } catch { return(Check.NullReturn(await NoneAsync())); } }
public MB Bind <MONADB, MB, B>(TryAsync <A> ma, Func <A, MB> f) where MONADB : struct, Monad <Unit, Unit, MB, B> => default(MONADB).IdAsync(_ => ma.Try().ContinueWith(task => { try { return(task.IsFaulted ? default(MONADB).Fail(task.Exception) : task.IsCanceled ? default(MONADB).Fail(new TaskCanceledException()) : task.Result.IsFaulted ? default(MONADB).Fail(task.Result.Exception) : task.Result.IsBottom ? default(MONADB).Fail(new TaskCanceledException()) : f(task.Result.Value)); } catch (Exception e) { return(default(MONADB).Fail(e)); } }));
public async Task <B> MatchUnsafeAsync <B>(TryAsync <A> opt, Func <A, Task <B> > Some, Func <Task <B> > None) { try { var res = await opt.Try(); if (res.IsFaulted) { return(await None()); } else { return(await Some(res.Value)); } } catch { return(await None()); } }