static void Main(string[] args) { string word = "five"; // Note: We're creating an either with the left type as int and the right type as string. // You can assign either type to an either Either <int, string> amount = 5; amount = word; var emptyEither = new Either <int, string>(); // Note you can do the same transformations you did on a Box<T> on an Either because it too is a Monad and it too has a Bind(), Map(), Select() and SelectMany() extension method. // This transformation occurs on the right hand value, provided that the either contains the right hand value and not the left (this is the inbuilt validation or short-circuiting Monad idea in action) var resultA = amount.Bind(str => TransformRight(str)); // Extract EitherData from either once validated ie that its not a right value, run transform function. amount = 25; // notice that it's biased to its right value and only cares about running a transform on a right type. // The validation within Either's Bind() will check for a Right Type and then run the provided transform, if its left it will return what it has (25) but no transform will occur var resultB = amount.Bind(integer => TransformRight(integer)); // Wont run transformation because the validation will fail because its a left type. Console.WriteLine($"The value of resulta is '{resultA}' and the result of result b is '{resultB}' and an empty either looks like this '{emptyEither}' "); // notice how Either's bind function will extract the right part, if validation succeeds and runs the transformation as expected. Either <int, string> TransformRight(string extractedRight) { Either <int, string> result = extractedRight.ToUpper(); // Like all Bind functions we need to lift the result into the monad ie Either type return(result); } }
Either <AccountError, decimal> AccountBalanceById(uint accountId) { Either <AccountError, uint> existingAccountId = ExistingAccountId(accountId); Either <AccountError, decimal> accountBalance = existingAccountId.Bind(AccountBalance); return(accountBalance); }
internal static Either <TAccumulate, TRight> FoldImpl <TSource, TAccumulate, TRight>( this IEnumerable <TSource> source, TAccumulate seed, Func <TAccumulate, TSource, Either <TAccumulate, TRight> > accumulator, Func <Either <TAccumulate, TRight>, bool> predicate) { Debug.Assert(source != null); Debug.Assert(accumulator != null); Debug.Assert(predicate != null); Either <TAccumulate, TRight> retval = Either <TAccumulate, TRight> .OfLeft(seed); using (var iter = source.GetEnumerator()) { while (predicate(retval) && iter.MoveNext()) { if (retval == null) { continue; } retval = retval.Bind(val => accumulator(val, iter.Current)); } } return(retval); }
public void BindShouldSucceedWhenLeft() { // Arrange var value = "value"; var left = Left(value); Either <string, int> either = left; Func <int, Either <string, bool> > toTrueBoolWhenEitherRightAndIntOne = (i) => { if (i.Equals(1)) { return(Right(true)); } else { return(Left("false")); }; }; // Act var result = either.Bind(toTrueBoolWhenEitherRightAndIntOne); // Assert result.Left.Should().Be("value"); }
internal static Either <TSource, TRight> ReduceImpl <TSource, TRight>( this IEnumerable <TSource> source, Func <TSource, TSource, Either <TSource, TRight> > accumulator, Func <Either <TSource, TRight>, bool> predicate) { Debug.Assert(source != null); Debug.Assert(accumulator != null); Debug.Assert(predicate != null); using (var iter = source.GetEnumerator()) { if (!iter.MoveNext()) { throw new InvalidOperationException("Source sequence was empty."); } Either <TSource, TRight> retval = Either <TSource, TRight> .OfLeft(iter.Current); while (predicate(retval) && iter.MoveNext()) { if (retval == null) { continue; } retval = retval.Bind(val => accumulator(val, iter.Current)); } return(retval); } }
public static Either <TLeft, TRightOutput> SelectSafe <TLeft, TRightInput, TRightMedium, TRightOutput>( this Either <TLeft, TRightInput> source, Func <TRightInput, Either <TLeft, TRightMedium> > mediumSelector, Func <TRightInput, TRightMedium, TRightOutput> resultSelector) { return(source.Bind(rightInput => mediumSelector(rightInput) .Map(rightMedium => resultSelector(rightInput, rightMedium)))); }
public void should_bind_on_right_values() { Either <string, int> sut = Functional.Right(10); Either <string, int> Double(int i) { return(Functional.Right(i * 2)); } var result = sut.Bind(Double); var match = result.Match(l => - 1, r => r); match.Should().Be(20); }
public void should_bind_on_right_values_on_failing_functions() { Either <string, int> sut = Right(10); Either <string, int> Double(int i) { return(Left("some error")); } var result = sut.Bind(Double); var match = result.Match(l => l, r => "should not happen"); match.Should().Be("some error"); }
public void should_bind_on_left_values() { Either <string, int> sut = Functional.Left("some error"); Either <string, int> Double(int i) { return(Functional.Right(i * 2)); } var result = sut.Bind(Double); var match = result.Match(l => l, r => "should not happen"); match.Should().Be("some error"); }
/// <summary> /// This methods extracts the value of a RETURN structure (BAPIRET or BAPIRET2) and processes it's value as /// left value if return contains a non-successful result (abort or error). /// This method accepts a EitherAsync with any right value. /// </summary> /// <param name="self"></param> /// <returns>A <see cref="EitherAsync{RfcErrorInfo,IFunction}"/> with the function as right value or the left value.</returns> public static Either <RfcErrorInfo, IFunction> HandleReturn(this Either <RfcErrorInfo, IFunction> self) { return(self.Bind(f => ( from ret in f.GetStructure("RETURN") from type in ret.GetField <string>("TYPE") from id in ret.GetField <string>("ID") from number in ret.GetField <string>("NUMBER") from message in ret.GetField <string>("MESSAGE") from v1 in ret.GetField <string>("MESSAGE_V1") from v2 in ret.GetField <string>("MESSAGE_V2") from v3 in ret.GetField <string>("MESSAGE_V3") from v4 in ret.GetField <string>("MESSAGE_V4") from _ in ErrorOrResult(f, type, id, number, message, v1, v2, v3, v4) select f))); }
// Either - Exception handling static void Eleven() { Option <string> result = GetHtml("invalidurl"); // None. ie it will swallow the exception Either <Exception, string> resultb = GetHtmlE("invalidurl"); // Left(System.InvalidOperationException) // Did the request throw an exception or return html? resultb.Match( Left: ex => HandleException(ex), Right: ProcessPipeline ); // Keep in the elevated context var resultc = resultb.Map(x => x.Substring(0, 1)); // if not an Exception ie Right, then apply a lambda expression // Bind an Either<Exception, string> with an Either<Exception, string> var resultd = resultb.Bind(DoSomething); }
public void Bind_Error_ShouldInvokeFunc() { var result = value.Bind(IsPositive); Assert.AreEqual(new Either <Exception, bool>(true), result); }
public static Either <RfcErrorInfo, TDataContainer> SetField <TDataContainer, T>(this Either <RfcErrorInfo, TDataContainer> self, string name, T value) where TDataContainer : IDataContainer { return(self.Bind(s => s.SetField(name, value).Map(u => s))); }
public void Bind_Error_ShouldKeepLeft() { var result = error.Bind(IsPositive); Assert.AreEqual(new Either <Exception, bool>(exception), result); }
static public Either <RfcErrorInfo, IEnumerable <TResult> > MapStructure <TResult>(this Either <RfcErrorInfo, ITable> eitherTable, Func <IStructure, Either <RfcErrorInfo, TResult> > mapperFunc) { return(eitherTable.Bind(table => table.Rows.Map(mapperFunc).Traverse(l => l))); }
static public Either <RfcErrorInfo, TResult> MapStructure <TCont, TResult>(this Either <RfcErrorInfo, TCont> self, string structureName, Func <IStructure, Either <RfcErrorInfo, TResult> > mapperFunc) where TCont : IDataContainer { return(self.Bind(s => s.GetStructure(structureName).Bind(mapperFunc))); }
public static Either <RfcErrorInfo, T> GetField <T>(this Either <RfcErrorInfo, IFunction> self, string name) { return(self.Bind(s => s.GetField <T>(name))); }
public static Either <RfcErrorInfo, TDataContainer> SetStructure <TDataContainer, TResult>(this Either <RfcErrorInfo, TDataContainer> self, string structureName, Func <Either <RfcErrorInfo, IStructure>, TResult> map) where TDataContainer : IDataContainer { return(self.Bind(dc => dc.GetStructure(structureName).Use(used => used.Apply(map).Apply(_ => used)).Map(_ => dc))); }
public static Either <X, B> SelectMany <X, A, B>(this Either <X, A> either, Func <A, Either <X, B> > selectManyFunc) { return(either.Bind(selectManyFunc)); }
public static Either <L, R> Flatten <L, R>(this Either <L, Either <L, R> > ma) => ma.Bind(identity);
public static Either <X, C> SelectMany <X, A, B, C>(this Either <X, A> either, Func <A, Either <X, B> > selectManyFunc, Func <A, B, C> combineFunc) { return(either.Bind(a => selectManyFunc(a).Bind(b => Either.Right <X, C>(combineFunc(a, b))))); }
// 1. Implement Apply for Either and Exceptional static Either <L, R> Apply <L, T, R>(this Either <L, Func <T, R> > eitherF, Either <L, T> eitherT) => eitherT.Bind(t => eitherF.Bind <L, Func <T, R>, R>(f => f(t)));
public static Either <TFailure, Option <TResult> > MapO <TFailure, TSource, TResult>( this Either <TFailure, Option <TSource> > @this, Func <TSource, Either <TFailure, TResult> > f) => @this.Bind(opt => opt.Match(t => f(t).Map(Optional), () => Right <TFailure, Option <TResult> >(Option <TResult> .None)));
public static Either <X, A> Join <X, A>(this Either <X, Either <X, A> > either) { return(either.Bind(a => a)); }
public static Either <L, RR> SelectMany <L, R, RR>(this Either <L, R> either, Func <R, Either <L, RR> > func) => either.Bind(func);
public static Either <X, B> Ap <X, A, B>(this Either <X, Func <A, B> > f, Either <X, A> arg) { return(f.Bind(f0 => arg.Map(f0))); }
public static Either <TLeft, TRightOutput> SelectSafe <TLeft, TRightInput, TRightOutput>( this Either <TLeft, TRightInput> source, Func <TRightInput, Either <TLeft, TRightOutput> > selector) { return(source.Bind(selector)); }