Created
April 23, 2013 22:29
-
-
Save dtchepak/5447958 to your computer and use it in GitHub Desktop.
The @xerxesb enum catamorphism. (Ignore the equality members boilerplate)
This file contains hidden or 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 NUnit.Framework; | |
using Shouldly; | |
public class Mushroom { } | |
public sealed class Xenum : IEquatable<Xenum> { | |
private readonly Mushroom _mushroom; | |
private readonly string _s; | |
private readonly int _a; | |
private readonly int _b; | |
private readonly int _type; | |
private Xenum(int a, int b) { _a = a; _b = b; _type = 0; } | |
private Xenum(string s) { _s = s; _type = 1; } | |
private Xenum(Mushroom mushroom) { _mushroom = mushroom; _type = 2; } | |
public static Xenum SomeNumbers(int a, int b) { return new Xenum(a, b); } | |
public static Xenum AString(string s) { return new Xenum(s); } | |
public static Xenum BadgerBadgerBadger(Mushroom m) { return new Xenum(m); } | |
public static T Cata<T>(Xenum x, Func<int, int, T> someNumbers, Func<string, T> aString, Func<Mushroom, T> badgers) { | |
switch (x._type) { | |
case 0: return someNumbers(x._a, x._b); | |
case 1: return aString(x._s); | |
case 2: return badgers(x._mushroom); | |
default: throw new InvalidOperationException(); | |
} | |
} | |
public bool Equals(Xenum other) { | |
if (ReferenceEquals(null, other)) return false; | |
if (ReferenceEquals(this, other)) return true; | |
return Equals(_mushroom, other._mushroom) && string.Equals(_s, other._s) && _a == other._a && _b == other._b && _type == other._type; | |
} | |
public override bool Equals(object obj) { | |
if (ReferenceEquals(null, obj)) return false; | |
if (ReferenceEquals(this, obj)) return true; | |
return obj is Xenum && Equals((Xenum) obj); | |
} | |
public override int GetHashCode() { | |
unchecked { | |
var hashCode = (_mushroom != null ? _mushroom.GetHashCode() : 0); | |
hashCode = (hashCode*397) ^ (_s != null ? _s.GetHashCode() : 0); | |
hashCode = (hashCode*397) ^ _a; | |
hashCode = (hashCode*397) ^ _b; | |
hashCode = (hashCode*397) ^ _type; | |
return hashCode; | |
} | |
} | |
} | |
public class XenumTests { | |
[Test] | |
public void IdentityFunctionWhenGivenOriginalCtorFunctions() { | |
/* "A function that produces an identity, given constructors for a data type, is called its catamorphism." | |
* src: @dibblego, http://dl.dropboxusercontent.com/u/7810909/media/doc/list-folds.pdf */ | |
var numbers = Xenum.SomeNumbers(6, 7); | |
var astring = Xenum.AString("hello world"); | |
var badgers = Xenum.BadgerBadgerBadger(new Mushroom()); | |
Func<Xenum, Xenum> idFunc = x => Xenum.Cata(x, Xenum.SomeNumbers, Xenum.AString, Xenum.BadgerBadgerBadger); | |
numbers.ShouldBe(idFunc(numbers)); | |
astring.ShouldBe(idFunc(astring)); | |
badgers.ShouldBe(idFunc(badgers)); | |
} | |
[Test] | |
public void ConvertAnyXenumToSomeValue() { | |
var numbers = Xenum.SomeNumbers(6, 7); | |
var astring = Xenum.AString("hello world"); | |
var badgers = Xenum.BadgerBadgerBadger(new Mushroom()); | |
Func<Xenum, string> describe = x => Xenum.Cata(x, (a,b) => "numbers", s => "string", m => "mushroom"); | |
describe(numbers).ShouldBe("numbers"); | |
describe(astring).ShouldBe("string"); | |
describe(badgers).ShouldBe("mushroom"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment