Created
August 15, 2016 12:55
-
-
Save lemonxah/afa85062979023da240ae7c65c160b34 to your computer and use it in GitHub Desktop.
Option Monad example for 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; | |
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 { } | |
} |
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 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); | |
} | |
} | |
} |
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
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