Skip to content

Instantly share code, notes, and snippets.

@ElemarJR
Created November 28, 2016 15:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ElemarJR/69d301a5cdb08f1a666bbdc679e55eab to your computer and use it in GitHub Desktop.
Save ElemarJR/69d301a5cdb08f1a666bbdc679e55eab to your computer and use it in GitHub Desktop.
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