Skip to content

Instantly share code, notes, and snippets.

@lemonxah
Created August 15, 2016 12:55
Show Gist options
  • Save lemonxah/afa85062979023da240ae7c65c160b34 to your computer and use it in GitHub Desktop.
Save lemonxah/afa85062979023da240ae7c65c160b34 to your computer and use it in GitHub Desktop.
Option Monad example for C#
using System;
namespace Functional {
public class GetOnEmptyOptionException : Exception { }
public interface Some { }
public interface None { }
public abstract class Option {
public static bool operator ==(Option a, Option b) =>
!ReferenceEquals(a, null) && !ReferenceEquals(b, null) && a.Equals(b);
public static bool operator !=(Option a, Option b) => !(a == b);
public static Option<A> None<A>() => new None<A>();
public static Option<A> Some<A>(A a) => new Some<A>(a);
}
public static class OptionOps {
public static Option<B> map<A, B>(this Option<A> oa, Func<A, B> f) => bind(oa, a => Option.Some(f(a)));
public static Option<B> bind<A, B>(this Option<A> oa, Func<A, Option<B>> f) {
if (oa.isEmpty) return Option.None<B>();
else return f(oa.get);
}
}
public abstract class Option<A> : Option {
public A get { get; }
public bool isDefined { get; }
public bool isEmpty { get { return !isDefined; } }
public Option() { isDefined = false; }
public Option(A a) { this.get = a; isDefined = true; }
public override string ToString() {
if (isEmpty) return "None";
else return $"Some({get.ToString()})";
}
public override bool Equals(object obj) {
var that = (Option<A>)obj;
return
(this.isEmpty && that.isEmpty) ||
(this.isDefined && that.isDefined && this.get.Equals(that.get));
}
public override int GetHashCode() {
return base.GetHashCode();
}
}
public class Some<A> : Option<A>, Some {
public Some(A a) : base(a) {}
}
public class None<A> : Option<A>, None { }
}
using System;
using static Functional.Option;
namespace Functional {
class MainClass {
public static void Main(string[] args) {
var o1 = Some("hello");
var o2 = o1.map(s => s.ToUpper());
Console.WriteLine(o1);
Console.WriteLine(o2);
Console.WriteLine(o2 == Some("HELLO"));
Console.WriteLine(o1.bind(s => countChars('l', s)));
Console.WriteLine(o1.bind(s => countChars('r', s)));
Console.WriteLine(o1.bind(count));
Console.ReadKey();
}
public static Option<int> count(String s) {
if (s == String.Empty) return None<int>();
else return Some(s.Length);
}
public static Option<int> countChars(Char c, String s) {
var count = 0;
foreach (var cc in s)
if (cc == c) count++;
if (count == 0)
return None<int>();
else
return Some(count);
}
}
}
Some(hello)
Some(HELLO)
True
Some(2)
None
Some(5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment