Created
December 7, 2016 02:21
-
-
Save Porges/144b55bd2027f141fcb691c3c103a570 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; | |
namespace Result | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var r = new Random(); | |
for (int i = 0; i < 10; ++i) | |
{ | |
var ex1 = | |
from value in MaybeFails(r, "first") | |
from value2 in MaybeFails(r, "second") | |
select value + value2; | |
Console.WriteLine(ex1); | |
// this exercises Select | |
//var ex2 = | |
// from value in MaybeFails(r, "only") | |
// let value1 = value + 1 | |
// select value1; | |
} | |
} | |
// A method that might succeed or fail: | |
private static Result<string, int> MaybeFails(Random rand, string failureMessage) | |
{ | |
if (rand.Next(3) == 2) | |
{ | |
return failureMessage; | |
} | |
return 123; | |
} | |
} | |
public abstract class Result<TFail, TSucceed> | |
{ | |
private Result() { } // only 2 instances | |
/// <summary> | |
/// Map the success argument. | |
/// </summary> | |
public abstract Result<TFail, TSucceed2> Map<TSucceed2>(Func<TSucceed, TSucceed2> projection); | |
/// <summary> | |
/// Pattern-match the result. | |
/// </summary> | |
public abstract T Match<T>(Func<TFail, T> onFailure, Func<TSucceed, T> onSuccess); | |
/// <summary> | |
/// Pattern-match the result with an action. | |
/// </summary> | |
public abstract void Match<T>(Action<TFail> onFailure, Action<TSucceed> onSuccess); | |
/// <summary> | |
/// Traditional .NET decomposition. | |
/// </summary> | |
public abstract bool TryGetValue(out TSucceed value); | |
private sealed class Fail : Result<TFail, TSucceed> | |
{ | |
private readonly TFail _value; | |
public Fail(TFail value) | |
{ | |
_value = value; | |
} | |
public override T Match<T>(Func<TFail, T> onFailure, Func<TSucceed, T> onSuccess) | |
=> onFailure(_value); | |
public override void Match<T>(Action<TFail> onFailure, Action<TSucceed> onSuccess) | |
=> onFailure(_value); | |
public override bool TryGetValue(out TSucceed value) | |
{ | |
value = default(TSucceed); | |
return false; | |
} | |
public override Result<TFail, TSucceed2> Map<TSucceed2>(Func<TSucceed, TSucceed2> projection) | |
=> _value; | |
public override string ToString() => $"Failure: {_value}"; | |
} | |
private sealed class Succeed : Result<TFail, TSucceed> | |
{ | |
private readonly TSucceed _value; | |
public Succeed(TSucceed value) | |
{ | |
_value = value; | |
} | |
public override T Match<T>(Func<TFail, T> onFailure, Func<TSucceed, T> onSuccess) | |
=> onSuccess(_value); | |
public override void Match<T>(Action<TFail> onFailure, Action<TSucceed> onSuccess) | |
=> onSuccess(_value); | |
public override bool TryGetValue(out TSucceed value) | |
{ | |
value = _value; | |
return true; | |
} | |
public override Result<TFail, TSucceed2> Map<TSucceed2>(Func<TSucceed, TSucceed2> projection) | |
=> projection(_value); | |
public override string ToString() => $"Success: {_value}"; | |
} | |
/// <summary> | |
/// Implicitly convert success. | |
/// </summary> | |
public static implicit operator Result<TFail, TSucceed>(TSucceed success) | |
=> new Succeed(success); | |
/// <summary> | |
/// Implicitly convert failure. | |
/// </summary> | |
public static implicit operator Result<TFail, TSucceed>(TFail failure) | |
=> new Fail(failure); | |
} | |
public static class ResultExtensions | |
{ | |
public static Result<TFail, TSuccess2> SelectMany<TFail, TSuccess, TSuccess2>( | |
this Result<TFail, TSuccess> me, | |
Func<TSuccess, Result<TFail, TSuccess2>> projection) | |
=> me.Match(f => f, projection); | |
public static Result<TFail, TResult> SelectMany<TFail, TSuccess, TSuccess2, TResult>( | |
this Result<TFail, TSuccess> me, | |
Func<TSuccess, Result<TFail, TSuccess2>> projection, | |
Func<TSuccess, TSuccess2, TResult> selector) | |
=> me.Match(f => f, s => projection(s).Match<Result<TFail, TResult>>(f2 => f2, s2 => selector(s, s2))); | |
public static Result<TFail, TSuccess2> Select<TFail, TSuccess, TSuccess2>( | |
this Result<TFail, TSuccess> me, | |
Func<TSuccess, TSuccess2> projection) | |
=> me.Map(projection); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment