7using System.Collections.Generic;
9#if ERRH_ADD_MAYBE_METHODS
32 internal abstract class Result<TSuccess, TMessage>
48 return string.Format(
"OK: {0} - {1}",
50 string.Join(Environment.NewLine, ok.
Messages.Select(v => v.ToString()))
55 return string.Format(
"Error: {0}",
56 string.Join(Environment.NewLine, bad.
Messages.Select(v => v.ToString()))
70 internal sealed class Ok<TSuccess, TMessage> :
Result<TSuccess, TMessage>
72 private readonly Tuple<TSuccess, IEnumerable<TMessage>>
_value;
74 public Ok(TSuccess success, IEnumerable<TMessage> messages)
79 throw new ArgumentNullException(nameof(messages));
82 _value = Tuple.Create(success, messages);
98 internal sealed class Bad<TSuccess, TMessage> :
Result<TSuccess, TMessage>
100 public Bad(IEnumerable<TMessage> messages)
103 if (messages ==
null)
105 throw new ArgumentException(nameof(messages));
117 internal static class Result
124 if (messages ==
null)
126 throw new ArgumentException(nameof(messages));
139 throw new ArgumentException(nameof(message));
160 throw new ArgumentException(nameof(message));
173 IEnumerable<TMessage> messages)
175 if (messages ==
null)
177 throw new ArgumentException(nameof(messages));
190 throw new ArgumentException(nameof(func));
196 Enumerable.Empty<Exception>()
214#if ERRH_ENABLE_INLINE_METHODS
215 [MethodImpl(MethodImplOptions.AggressiveInlining)]
225#if ERRH_ENABLE_INLINE_METHODS
226 [MethodImpl(MethodImplOptions.AggressiveInlining)]
236#if ERRH_ENABLE_INLINE_METHODS
237 [MethodImpl(MethodImplOptions.AggressiveInlining)]
243 throw new ArgumentException(nameof(message));
254#if ERRH_ENABLE_INLINE_METHODS
255 [MethodImpl(MethodImplOptions.AggressiveInlining)]
261 throw new ArgumentException(nameof(message));
270#if ERRH_ENABLE_INLINE_METHODS
271 [MethodImpl(MethodImplOptions.AggressiveInlining)]
281#if ERRH_ENABLE_INLINE_METHODS
282 [MethodImpl(MethodImplOptions.AggressiveInlining)]
285 Func<TSuccess, IEnumerable<TMessage>, TResult> successFunc,
286 Func<IEnumerable<TMessage>, TResult> failureFunc,
289 if (successFunc ==
null)
291 throw new ArgumentException(nameof(successFunc));
294 if (failureFunc ==
null)
296 throw new ArgumentException(nameof(failureFunc));
315#if ERRH_ENABLE_INLINE_METHODS
316 [MethodImpl(MethodImplOptions.AggressiveInlining)]
320 Func<IEnumerable<TMessage>, TSuccess> raiseExn = msgs =>
322 throw new Exception(
string.Join(Environment.NewLine,
323 msgs.Select(m => m.ToString())
328 return Either((succ, _) => succ, raiseExn, result);
334#if ERRH_ENABLE_INLINE_METHODS
335 [MethodImpl(MethodImplOptions.AggressiveInlining)]
340 if (messages ==
null)
342 throw new ArgumentException(nameof(messages));
348 messages.Concat(msgs)
354 return Either(successFunc, failureFunc, result);
361#if ERRH_ENABLE_INLINE_METHODS
362 [MethodImpl(MethodImplOptions.AggressiveInlining)]
370 throw new ArgumentException(nameof(func));
374 (succ, msgs) => MergeMessages(msgs, func(succ));
379 return Either(successFunc, failureFunc, result);
385#if ERRH_ENABLE_INLINE_METHODS
386 [MethodImpl(MethodImplOptions.AggressiveInlining)]
391 return Bind(x => x, result);
398#if ERRH_ENABLE_INLINE_METHODS
399 [MethodImpl(MethodImplOptions.AggressiveInlining)]
402 Result<Func<TValue, TSuccess>, TMessage> wrappedFunction,
405 if (wrappedFunction ==
null)
407 throw new ArgumentException(nameof(wrappedFunction));
439#if ERRH_ENABLE_INLINE_METHODS
440 [MethodImpl(MethodImplOptions.AggressiveInlining)]
445 return Apply(
Ok<Func<TValue, TSuccess>, TMessage>(func), result);
451#if ERRH_ENABLE_INLINE_METHODS
452 [MethodImpl(MethodImplOptions.AggressiveInlining)]
455 Func<TSuccess, Func<TMessage, TSuccess1>> func,
459 return Apply(Lift(func, first), second);
466#if ERRH_ENABLE_INLINE_METHODS
467 [MethodImpl(MethodImplOptions.AggressiveInlining)]
472 return Lift(Enumerable.Reverse,
474 Result<IEnumerable<TSuccess>, TMessage>>(
null,
477 if (result.Tag == ResultType.Ok &&
478 next.Tag == ResultType.Ok)
480 Ok<IEnumerable<TSuccess>, TMessage> ok1 =
481 (Ok<IEnumerable<TSuccess>, TMessage>)
484 Ok<TSuccess, TMessage> ok2 =
485 (Ok<TSuccess, TMessage>)next;
488 new Ok<IEnumerable<TSuccess>,
491 .Concat(new[] { ok2.Success }
493 .Concat(ok1.Success),
494 ok1.Messages.Concat(ok2.Messages)
503 IEnumerable<TMessage> m1 =
504 result.Tag == ResultType.Ok
505 ? ((Ok<IEnumerable<TSuccess>,
508 : ((Bad<TSuccess, TMessage>)next)
511 IEnumerable<TMessage> m2 =
512 result.Tag == ResultType.Bad
513 ? ((Bad<IEnumerable<TSuccess>,
516 : ((Ok<TSuccess, TMessage>)next)
519 return new Bad<IEnumerable<TSuccess>,
520 TMessage>(m1.Concat(m2));
523 Bad<IEnumerable<TSuccess>, TMessage> bad1 =
524 (
Bad<IEnumerable<TSuccess>, TMessage>)
552#if ERRH_ENABLE_INLINE_METHODS
553 [MethodImpl(MethodImplOptions.AggressiveInlining)]
556 Action<TSuccess, IEnumerable<TMessage>> ifSuccess,
557 Action<IEnumerable<TMessage>> ifFailure)
559 if (ifSuccess ==
null)
561 throw new ArgumentException(nameof(ifSuccess));
564 if (ifFailure ==
null)
566 throw new ArgumentException(nameof(ifFailure));
585#if ERRH_ENABLE_INLINE_METHODS
586 [MethodImpl(MethodImplOptions.AggressiveInlining)]
589 Func<TSuccess, IEnumerable<TMessage>, TResult>
591 Func<IEnumerable<TMessage>, TResult> ifFailure)
593 return Trial.Either(ifSuccess, ifFailure, result);
599#if ERRH_ENABLE_INLINE_METHODS
600 [MethodImpl(MethodImplOptions.AggressiveInlining)]
603 Func<TSuccess, TResult> func)
605 return Trial.Lift(func, result);
612#if ERRH_ENABLE_INLINE_METHODS
613 [MethodImpl(MethodImplOptions.AggressiveInlining)]
618 return Trial.Collect(values);
625#if ERRH_ENABLE_INLINE_METHODS
626 [MethodImpl(MethodImplOptions.AggressiveInlining)]
635 IEnumerable<Result<TSuccess, TMessage>> values = ok.
Success;
660#if ERRH_ENABLE_INLINE_METHODS
661 [MethodImpl(MethodImplOptions.AggressiveInlining)]
667 return Trial.Bind(func, result);
675#if ERRH_ENABLE_INLINE_METHODS
676 [MethodImpl(MethodImplOptions.AggressiveInlining)]
681 Func<TSuccess, TValue, TResult> mapperFunc)
685 throw new ArgumentException(nameof(func));
688 if (mapperFunc ==
null)
690 throw new ArgumentException(nameof(mapperFunc));
693 Func<TSuccess, Func<TValue, TResult>> curriedMapper = suc => val => mapperFunc(suc, val);
699 > liftedMapper = (a, b) =>
Trial.Lift2(curriedMapper, a, b);
702 return liftedMapper(result, v);
708#if ERRH_ENABLE_INLINE_METHODS
709 [MethodImpl(MethodImplOptions.AggressiveInlining)]
713 Func<TSuccess, TResult> func)
715 return Trial.Lift(func, result);
721#if ERRH_ENABLE_INLINE_METHODS
722 [MethodImpl(MethodImplOptions.AggressiveInlining)]
730 throw new Exception(
string.Format(
"Result was a success: {0} - {1}",
732 string.Join(Environment.NewLine,
733 ok.
Messages.Select(m => m.ToString())
747#if ERRH_ENABLE_INLINE_METHODS
748 [MethodImpl(MethodImplOptions.AggressiveInlining)]
761 throw new Exception(
string.Format(
"Result was an error: {0}",
762 string.Join(Environment.NewLine, bad.
Messages.Select(m => m.ToString()))
779 return Enumerable.Empty<TMessage>();
782#if ERRH_ADD_MAYBE_METHODS
783#if ERRH_ENABLE_INLINE_METHODS
784 [MethodImpl(MethodImplOptions.AggressiveInlining)]
798 return Maybe.Nothing<TSuccess>();
The Maybe type models an optional value. A value of type Maybe a either contains a value of type a (r...
Represents the result of a failed computation.
Bad(IEnumerable< TMessage > messages)
IEnumerable< TMessage > Messages
Represents the result of a successful computation.
IEnumerable< TMessage > Messages
readonly Tuple< TSuccess, IEnumerable< TMessage > > _value
Ok(TSuccess success, IEnumerable< TMessage > messages)
Extensions methods for easier usage.
Represents the result of a computation.
static Result< TSuccess, TMessage > Succeed< TSuccess, TMessage >(TSuccess value)
Creates a Success result with the given value.
static Result< TSuccess, Exception > Try< TSuccess >(Func< TSuccess > func)
Executes the given function on a given success or captures the failure.
override string ToString()
static Result< TSuccess, TMessage > FailWith< TSuccess, TMessage >(IEnumerable< TMessage > messages)
Creates a Failure result with the given messages.
static Result< TSuccess, TMessage > Ok< TSuccess, TMessage >(TSuccess value)
Wraps a value in a Success.
static Result< TSuccess, TMessage > Pass< TSuccess, TMessage >(TSuccess value)
Wraps a value in a Success.
static TResult Either< TSuccess, TMessage, TResult >(Func< TSuccess, IEnumerable< TMessage >, TResult > successFunc, Func< IEnumerable< TMessage >, TResult > failureFunc, Result< TSuccess, TMessage > trialResult)
Takes a Result and maps it with successFunc if it is a Success otherwise it maps it with failureFunc.
static Result< TSuccess, TMessage > Apply< TValue, TSuccess, TMessage >(Result< Func< TValue, TSuccess >, TMessage > wrappedFunction, Result< TValue, TMessage > result)
If the wrapped function is a success and the given result is a success the function is applied on the...
static Result< TSuccess, TMessage > Lift< TValue, TSuccess, TMessage >(Func< TValue, TSuccess > func, Result< TValue, TMessage > result)
Lifts a function into a Result container and applies it on the given result.
static bool Failed< TSuccess, TMessage >(Result< TSuccess, TMessage > result)
Returns true if the result was not successful.
static Result< TSuccess1, TMessage1 > Lift2< TSuccess, TMessage, TSuccess1, TMessage1 >(Func< TSuccess, Func< TMessage, TSuccess1 > > func, Result< TSuccess, TMessage1 > first, Result< TMessage, TMessage1 > second)
Promote a function to a monad/applicative, scanning the monadic/applicative arguments from left to ri...
static Result< TSuccess, TMessage > Flatten< TSuccess, TMessage >(Result< Result< TSuccess, TMessage >, TMessage > result)
Flattens a nested result given the Failure types are equal.
static Result< IEnumerable< TSuccess >, TMessage > Collect< TSuccess, TMessage >(IEnumerable< Result< TSuccess, TMessage > > xs)
Collects a sequence of Results and accumulates their values. If the sequence contains an error the er...
static TSuccess ReturnOrFail< TSuccess, TMessage >(Result< TSuccess, TMessage > result)
If the given result is a Success the wrapped value will be returned. Otherwise the function throws an...
static Result< TSuccess, TMessage > Warn< TSuccess, TMessage >(TMessage message, TSuccess value)
Wraps a value in a Success and adds a message.
static Result< TSuccess, TMessage > Bind< TValue, TSuccess, TMessage >(Func< TValue, Result< TSuccess, TMessage > > func, Result< TValue, TMessage > result)
If the result is a Success it executes the given function on the value. Otherwise the exisiting failu...
static Result< TSuccess, TMessage > Fail< TSuccess, TMessage >(TMessage message)
Wraps a message in a Failure.
static Result< TSuccess, TMessage > MergeMessages< TSuccess, TMessage >(IEnumerable< TMessage > messages, Result< TSuccess, TMessage > result)
Appends the given messages with the messages in the given result.