Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Exceptional Monad in C#
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
You can’t perform that action at this time.