Created
November 28, 2016 15:54
-
-
Save ElemarJR/69d301a5cdb08f1a666bbdc679e55eab to your computer and use it in GitHub Desktop.
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
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace ConsoleApplication9 | |
{ | |
using static System.Console; | |
using static System.Math; | |
using static Helpers; | |
class Program | |
{ | |
public static void Main() | |
{ | |
WriteLine("Enter the first number: "); | |
var a = ReadLine(); | |
WriteLine("Enter the second number: "); | |
var b = ReadLine(); | |
Add(a, b).Match( | |
success: WriteLine, | |
failure: exceptions => exceptions.ForEach(WriteLine) | |
); | |
} | |
public static int Add(int a, int b) => a + b; | |
public static Try<IEnumerable<string>, int> Add(Untrusted<string> a, Untrusted<string> b) | |
=> Try<IEnumerable<string>, Func<int, int, int>>.Of(Add) | |
.Apply(ParseInt(a)) | |
.Apply(ParseInt(b)); | |
static Try<string, int> ParseInt(Untrusted<string> input) | |
{ | |
var output = 0; | |
return input.Validate<string, int>( | |
s => int.TryParse(s, out output), | |
onFailure: s => $"Cannot parse '{s}' as an integer.", | |
onSuccess: _ => output | |
); | |
} | |
} | |
public partial class Helpers | |
{ | |
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) | |
{ | |
foreach (var elem in source) | |
{ | |
action(elem); | |
} | |
} | |
} | |
public partial struct Try<TFailure, TSuccess> | |
{ | |
public Option<TFailure> OptionalFailure | |
=> IsFailure ? Some(Failure) : None; | |
public Option<TSuccess> OptionalSuccess | |
=> IsSucess ? Some(Success) : None; | |
} | |
public partial class Helpers | |
{ | |
public static Try<IEnumerable<TFailure>, Func<TB, TResult>> Apply<TFailure, TA, TB, TResult>( | |
this Try<IEnumerable<TFailure>, Func<TA, TB, TResult>> func, Try<TFailure, TA> arg | |
) | |
{ | |
return arg.Match( | |
failure: e => Try<IEnumerable<TFailure>, Func<TB, TResult>>.Of( | |
func.OptionalFailure.GetOrElse(Enumerable.Empty<TFailure>).Concat(new[] { e }) | |
), | |
success: a => func.Match( | |
failure: Try<IEnumerable<TFailure>, Func<TB, TResult>>.Of, | |
success: f => Try<IEnumerable<TFailure>, Func<TB, TResult>>.Of(b => f(a, b)) | |
) | |
); | |
} | |
public static Try<IEnumerable<TFailure>, TResult> Apply<TFailure, TA, TResult>( | |
this Try<IEnumerable<TFailure>, Func<TA, TResult>> func, Try<TFailure, TA> arg | |
) | |
{ | |
return arg.Match( | |
failure: e => Try<IEnumerable<TFailure>, TResult>.Of( | |
func.OptionalFailure.GetOrElse(Enumerable.Empty<TFailure>).Concat(new[] { e }) | |
), | |
success: a => func.Match( | |
failure: Try<IEnumerable<TFailure>, TResult>.Of, | |
success: f => Try<IEnumerable<TFailure>, TResult>.Of(f(a)) | |
) | |
); | |
} | |
} | |
public partial struct Option<T> | |
{ | |
internal T Value { get; } | |
public bool IsSome { get; } | |
public bool IsNone => !IsSome; | |
internal Option(T value, bool isSome) | |
{ | |
Value = value; | |
IsSome = isSome; | |
} | |
public TR Match<TR>(Func<T, TR> some, Func<TR> none) | |
=> IsSome ? some(Value) : none(); | |
public Unit Match(Action<T> some, Action none) | |
=> Match(ToFunc(some), ToFunc(none)); | |
public static readonly Option<T> None = new Option<T>(); | |
public static implicit operator Option<T>(T value) | |
=> Some(value); | |
public static implicit operator Option<T>(NoneType _) | |
=> None; | |
} | |
public static class Option | |
{ | |
public static Option<T> Of<T>(T value) | |
=> new Option<T>(value, value != null); | |
public static Option<TR> Map<T, TR>( | |
this Option<T> @this, | |
Func<T, TR> mapfunc | |
) => | |
@this.IsSome | |
? Some(mapfunc(@this.Value)) | |
: None; | |
public static T GetOrElse<T>( | |
this Option<T> @this, | |
Func<T> fallback | |
) => | |
@this.Match( | |
some: value => value, | |
none: fallback | |
); | |
public static T GetOrElse<T>( | |
this Option<T> @this, | |
T @else | |
) => | |
GetOrElse(@this, () => @else); | |
} | |
public struct NoneType { } | |
public static partial class Helpers | |
{ | |
public static Option<T> Some<T>(T value) => Option.Of(value); | |
public static readonly NoneType None = new NoneType(); | |
public static Func<Unit> ToFunc(Action action) => () => | |
{ | |
action(); | |
return Unit(); | |
}; | |
} | |
public partial class Helpers | |
{ | |
public static Try<TFailure, Func<TB, TC, TResult>> Apply<TFailure, TA, TB, TC, TResult>( | |
this Try<TFailure, Func<TA, TB, TC, TResult>> func, Try<TFailure, TA> arg | |
) | |
{ | |
return arg.Match( | |
failure: e => e, | |
success: a => func.Match( | |
failure: e2 => e2, | |
success: f => Try<TFailure, Func<TB, TC, TResult>>.Of((b, c) => f(a, b, c)) | |
) | |
); | |
} | |
public static Try<TFailure, Func<TB, TResult>> Apply<TFailure, TA, TB, TResult>( | |
this Try<TFailure, Func<TA, TB, TResult>> func, Try<TFailure, TA> arg | |
) | |
{ | |
return arg.Match( | |
failure: e => e, | |
success: a => func.Match( | |
failure: e2 => e2, | |
success: f => Try<TFailure, Func<TB, TResult>>.Of(b => f(a, b)) | |
) | |
); | |
} | |
public static Try<TFailure, TResult> Apply<TFailure, TA, TResult>( | |
this Try<TFailure, Func<TA, TResult>> func, Try<TFailure, TA> arg | |
) => arg.Match( | |
failure: e => e, | |
success: a => func.Match( | |
failure: e2 => e2, | |
success: f => Try<TFailure, TResult>.Of(f(a)) | |
) | |
); | |
} | |
public partial struct Try<TFailure, TSuccess> | |
{ | |
public static Try<TFailure, TSuccess> Of(TSuccess obj) => obj; | |
public static Try<TFailure, TSuccess> Of(TFailure obj) => obj; | |
} | |
public struct Untrusted<T> | |
{ | |
private readonly T _value; | |
private Untrusted(T value) | |
{ | |
_value = value; | |
} | |
public static implicit operator Untrusted<T>(T value) | |
=> new Untrusted<T>(value); | |
public Try<TFailure, TSuccess> Validate<TFailure, TSuccess>( | |
Func<T, bool> validation, | |
Func<T, TFailure> onFailure, | |
Func<T, TSuccess> onSuccess | |
) => validation(_value) | |
? onSuccess(_value) | |
: (Try<TFailure, TSuccess>)onFailure(_value); | |
} | |
public static class Untrusted | |
{ | |
public static Untrusted<T> Of<T>(T value) | |
=> value; | |
} | |
public partial struct Try<TFailure, TSuccess> | |
{ | |
internal TFailure Failure { get; } | |
internal TSuccess Success { get; } | |
public bool IsFailure { get; } | |
public bool IsSucess => !IsFailure; | |
internal Try(TFailure failure) | |
{ | |
IsFailure = true; | |
Failure = failure; | |
Success = default(TSuccess); | |
} | |
internal Try(TSuccess success) | |
{ | |
IsFailure = false; | |
Failure = default(TFailure); | |
Success = success; | |
} | |
public static implicit operator Try<TFailure, TSuccess>(TFailure failure) | |
=> new Try<TFailure, TSuccess>(failure); | |
public static implicit operator Try<TFailure, TSuccess>(TSuccess success) | |
=> new Try<TFailure, TSuccess>(success); | |
public TResult Match<TResult>(Func<TFailure, TResult> failure, Func<TSuccess, TResult> success) | |
=> IsFailure ? failure(Failure) : success(Success); | |
public Unit Match(Action<TFailure> failure, Action<TSuccess> success) | |
=> Match(ToFunc(failure), ToFunc(success)); | |
} | |
public partial struct Unit | |
{ } | |
public static partial class Helpers | |
{ | |
private static readonly Unit unit = new Unit(); | |
public static Unit Unit() => unit; | |
public static Func<T, Unit> ToFunc<T>(Action<T> action) => o => | |
{ | |
action(o); | |
return Unit(); | |
}; | |
} | |
static class Extensions | |
{ | |
public static Func<TB, TResult> Apply<TA, TB, TResult>( | |
this Func<TA, TB, TResult> func, | |
TA a) => b => func(a, b); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment