Last active
November 30, 2018 13:45
-
-
Save bradphelan/6154972 to your computer and use it in GitHub Desktop.
Exceptional Monad in C#
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; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Reactive.Linq; | |
namespace ReactiveUI.Utils | |
{ | |
// From http://stackoverflow.com/questions/10772727/exception-or-either-monad-in-c-sharp | |
public class Exceptional<T> | |
{ | |
public bool HasException { get; private set; } | |
public Exception Exception { get; private set; } | |
public T Value { get; private set; } | |
public Exceptional(T value) | |
{ | |
HasException = false; | |
Value = value; | |
} | |
public Exceptional(Exception exception) | |
{ | |
HasException = true; | |
Exception = exception; | |
} | |
public Exceptional(Func<T> getValue) | |
{ | |
try | |
{ | |
Value = getValue(); | |
HasException = false; | |
} | |
catch (Exception exc) | |
{ | |
Exception = exc; | |
HasException = true; | |
} | |
} | |
// Returns the exception message if it exists or an empty string | |
public string ToMessage() | |
{ | |
return this.HasException ? Exception.Message : ""; | |
} | |
public override string ToString() | |
{ | |
return (this.HasException ? Exception.GetType().Name : ((Value != null) ? Value.ToString() : "null")); | |
} | |
} | |
public static class ExceptionalMonadExtensions | |
{ | |
public static Exceptional<T> ToExceptional<T>(this T value) | |
{ | |
return new Exceptional<T>(value); | |
} | |
public static Exceptional<T> ToExceptional<T>(this Exception ex) | |
{ | |
return new Exceptional<T>(ex); | |
} | |
public static Exceptional<T> ToExceptional<T>(this Func<T> getValue) | |
{ | |
return new Exceptional<T>(getValue); | |
} | |
public static Exceptional<U> Select<T, U>(this Exceptional<T> value, Func<T, U> k) | |
{ | |
return (value.HasException) | |
? new Exceptional<U>(value.Exception) | |
: k(value.Value).ToExceptional(); | |
} | |
public static Exceptional<U> SelectMany<T, U>(this Exceptional<T> value, Func<T, Exceptional<U>> k) | |
{ | |
return (value.HasException) | |
? new Exceptional<U>(value.Exception) | |
: k(value.Value); | |
} | |
public static Exceptional<V> SelectMany<T, U, V>(this Exceptional<T> value, Func<T, Exceptional<U>> k, Func<T, U, V> m) | |
{ | |
return value.SelectMany(t => k(t).SelectMany(u => m(t, u).ToExceptional())); | |
} | |
} | |
public static class Exceptional | |
{ | |
public static Exceptional<T> From<T>(T value) | |
{ | |
return value.ToExceptional(); | |
} | |
public static Exceptional<T> Execute<T>(Func<T> getValue) | |
{ | |
return getValue.ToExceptional(); | |
} | |
public static Exceptional<T> Execute<U0, T>( Func<U0, T> fn, U0 u0 ) | |
{ | |
return Exceptional.Execute(() => fn(u0)); | |
} | |
public static Exceptional<T> Execute<U0,U1, T>( Func<U0,U1, T> fn, U0 u0, U1 u1 ) | |
{ | |
return Exceptional.Execute(() => fn(u0,u1)); | |
} | |
public static Exceptional<T> Execute<U0,U1,U2,T>( Func<U0,U1,U2,T> fn, U0 u0, U1 u1,U2 u2 ) | |
{ | |
return Exceptional.Execute(() => fn(u0,u1,u2)); | |
} | |
public static Exceptional<T> Execute<U0,U1,U2,U3,T>( Func<U0,U1,U2,U3,T> fn, U0 u0, U1 u1,U2 u2,U3 u3 ) | |
{ | |
return Exceptional.Execute(() => fn(u0,u1,u2,u3)); | |
} | |
public static Exceptional<T> Execute<U0,U1,U2,U3,U4,T>( Func<U0,U1,U2,U3,U4,T> fn, U0 u0, U1 u1,U2 u2,U3 u3, U4 u4 ) | |
{ | |
return Exceptional.Execute(() => fn(u0,u1,u2,u3,u4)); | |
} | |
} | |
public static class ExceptionalExtensions | |
{ | |
public static Exceptional<U> ThenExecute<T, U>(this Exceptional<T> value, Func<T, U> getValue) | |
{ | |
return value.SelectMany(x => Exceptional.Execute(() => getValue(x))); | |
} | |
public static IObservable<U> WithoutErrors<U>( this IObservable<Exceptional<U>> o ) | |
{ | |
return o.Where(v => !v.HasException).Select(v => v.Value); | |
} | |
public static T Catch<T>(this Exceptional<T> e, Func<Exception,T> fn){ | |
if (e.HasException) | |
{ | |
return fn(e.Exception); | |
} | |
return e.Value; | |
} | |
public static void Catch<T>(this Exceptional<T> e, Action<Exception> fn){ | |
if (e.HasException) | |
{ | |
fn(e.Exception); | |
} | |
} | |
public static IObservable<T> Catch<T>(this IObservable<Exceptional<T>> This, Func<Exception, T> t){ | |
return This | |
.Select(v => { | |
if ( v.HasException ) | |
{ | |
return t(v.Exception); | |
} | |
else | |
{ | |
return v.Value; | |
} | |
}); | |
} | |
public static IObservable<T> Catch<T>(this IObservable<Exceptional<T>> This, Action<Exception> t){ | |
return This | |
.Do(v => { | |
if ( v.HasException ) | |
{ | |
t(v.Exception); | |
} | |
}) | |
.WithoutErrors(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment