Skip to content

Instantly share code, notes, and snippets.

@Pzixel
Last active October 17, 2019 23:07
Show Gist options
  • Save Pzixel/fd4ccfcf011770075d53775eee13d8d8 to your computer and use it in GitHub Desktop.
Save Pzixel/fd4ccfcf011770075d53775eee13d8d8 to your computer and use it in GitHub Desktop.
void Main()
{
var v = from x in 10.AsResult()
from y in 0.AsResult()
select Result.Try (() => x/y);
v.Dump();
}
public interface IResult<T, E>
{
}
public class Ok<T, E> : IResult<T, E>
{
public T Value { get; }
public Ok(T value)
{
Value = value;
}
}
public class Error<T, E> : IResult<T, E>
{
public E Value { get; }
public Error(E value)
{
Value = value;
}
}
public static class Result
{
public static IResult<T, Exception> AsResult<T>(this T value) => new Ok<T, Exception>(value);
public static IResult<T, Exception> Try<T>(Func<T> func)
{
try
{
return new Ok<T, Exception>(func());
}
catch (Exception ex)
{
return new Error<T, Exception>(ex);
}
}
public static Task<IResult<T, Exception>> TryAsync<T>(Func<Task<T>> func) =>
func().ContinueWith(x => Try(() => x.Result));
public static IResult<TResult, E> Map<T, TResult, E>(this IResult<T, E> result, Func<T, TResult> map)
{
switch (result)
{
case Ok<T, E> ok:
return new Ok<TResult, E>(map(ok.Value));
case Error<T, E> err:
return new Error<TResult, E>(err.Value);
default:
throw new InvalidOperationException($"Unknown result type {result.GetType().Name}");
}
}
public static async Task<IResult<TResult, E>> MapAsync<T, TResult, E>(this IResult<T, E> result, Func<T, Task<TResult>> map)
{
switch (result)
{
case Ok<T, E> ok:
return new Ok<TResult, E>(await map(ok.Value));
case Error<T, E> err:
return new Error<TResult, E>(err.Value);
default:
throw new InvalidOperationException($"Unknown result type {result.GetType().Name}");
}
}
public static IResult<T, EResult> MapError<T, E, EResult>(this IResult<T, E> result, Func<E, EResult> map)
{
switch (result)
{
case Ok<T, E> ok:
return new Ok<T, EResult>(ok.Value);
case Error<T, E> err:
return new Error<T, EResult>(map(err.Value));
default:
throw new InvalidOperationException($"Unknown result type {result.GetType().Name}");
}
}
public static IResult<TResult, E> Bind<T, TResult, E>(this IResult<T, E> result, Func<T, IResult<TResult, E>> bind)
{
switch (result)
{
case Ok<T, E> ok:
return bind(ok.Value);
case Error<T, E> err:
return new Error<TResult, E>(err.Value);
default:
throw new InvalidOperationException($"Unknown result type {result.GetType().Name}");
}
}
public static Task<IResult<TResult, E>> BindAsync<T, TResult, E>(this IResult<T, E> result, Func<T, Task<IResult<TResult, E>>> bind)
{
switch (result)
{
case Ok<T, E> ok:
return bind(ok.Value);
case Error<T, E> err:
return Task.FromResult((IResult<TResult, E>)new Error<TResult, E>(err.Value));
default:
throw new InvalidOperationException($"Unknown result type {result.GetType().Name}");
}
}
public static IResult<T, E> Scan<T, E>(this IResult<T, E> result, Action<T> onOk, Action<E> onError)
{
switch (result)
{
case Ok<T, E> ok:
onOk(ok.Value);
return result;
case Error<T, E> err:
onError(err.Value);
return result;
default:
throw new InvalidOperationException($"Unknown result type {result.GetType().Name}");
}
}
}
public static class ResultLinq
{
public static IResult<TResult, E> Select<T, E, TResult>(this IResult<T, E> value, Func<T, TResult> map) => value.Map(map);
public static IResult<TResult, E> SelectMany<T, E, TResult>(this IResult<T, E> value, Func<T, IResult<TResult, E>> bind) => value.Bind(bind);
public static IResult<TResult, E> SelectMany<TA, TB, E, TResult>(this IResult<TA, E> value, Func<TA, IResult<TB, E>> bind, Func<TA, TB, TResult> project)
{
switch (value)
{
case Error<TA, E> err:
return new Error<TResult, E>(err.Value);
case Ok<TA, E> oka:
var b = bind(oka.Value);
switch (b)
{
case Error<TB, E> err:
return new Error<TResult, E>(err.Value);
case Ok<TB, E> okb:
return new Ok<TResult, E>(project(oka.Value, okb.Value));
default:
throw new InvalidOperationException($"Unknown result type {value.GetType().Name}");
}
default:
throw new InvalidOperationException($"Unknown result type {value.GetType().Name}");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment