Skip to content

Instantly share code, notes, and snippets.

Created June 13, 2013 21:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/5777327 to your computer and use it in GitHub Desktop.
Save anonymous/5777327 to your computer and use it in GitHub Desktop.
A C# implementation of haskell's Either.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Util
{
public class Either<TLeft, TRight> : IEither<TLeft, TRight>
{
// Function demonstrating the use of Either.
public static void Test()
{
Action<Either<int, string>> doStuff =
(e) =>
{
Console.WriteLine(
"Result = " + e.Case(
(i) => i.ToString(),
(s) => s));
if (e.IsLeft)
{
Console.WriteLine(e / 2);
}
};
if (new Random().Next(2) == 0)
{
doStuff(10);
}
else
{
doStuff("test");
}
}
private class Container<T>
{
public T value;
static public implicit operator T(Container<T> c)
{
return c.value;
}
static public implicit operator Container<T>(T v)
{
return new Container<T>() { value = v };
}
}
private Container<TLeft> left = null;
private Container<TRight> right = null;
public bool IsLeft { get { return right == null; } }
public TLeft Left
{
get
{
if (!IsLeft)
{
throw new InvalidOperationException();
}
return left.value;
}
}
public TRight Right
{
get
{
if (IsLeft)
{
throw new InvalidOperationException();
}
return right.value;
}
}
private Either() { }
static public implicit operator Either<TLeft, TRight>(TLeft value)
{
return new Either<TLeft, TRight>() { left = value };
}
static public implicit operator TLeft(IEither<TLeft, TRight> from)
{
return from.Left;
}
static public implicit operator TRight(IEither<TLeft, TRight> from)
{
return from.Right;
}
static public implicit operator Either<TLeft, TRight>(TRight value)
{
return new Either<TLeft, TRight>() { right = value };
}
public U Case<U>(Func<TLeft, U> ifLeft, Func<TRight, U> ifRight)
{
return IsLeft ? ifLeft(Left) : ifRight(Right);
}
public void Case(Action<TLeft> ifLeft, Action<TRight> ifRight)
{
if (IsLeft) { ifLeft(Left); }
else { ifRight(Right); }
}
}
// To preserve covariance if you need it, but lose the fancy implicit conversions.
public interface IEither<out TLeft, out TRight>
{
public bool IsLeft { get; }
public TLeft Left { get; }
public TRight Right { get; }
public U Case<U>(Func<TLeft, U> ifLeft, Func<TRight, U> ifRight);
public U Case<U>(Action<TLeft, U> ifLeft, Action<TRight, U> ifRight);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment