Monads in C#?

VisualStudio 2015 and C# 6.0 are out available for preview!!

I decided that a good way to do that would be to try implement a couple of monads in C#. Monads offer a very nice way to separate core logic from the boilerplate code. They are used quite a lot in many programming languages, and in C# they are foundation for Linq. So, I was wondering how easy/hard it would be to implement them in pure C# (not with Linq) and would they end up being practical to use in a OOP language like C#?

Disclaimer: this really is a simplified and incomplete attempt – for a complete and more through take, you should go ahead and read more detailed blog posts here or here:

First, a basic intuition about monads:

monad = data container + some computation + public interface (‘From’ and ‘Bind’)

  • Data container – in C#, simply a class
  • Computation – repetitive logic that can be extracted from the main/core operation
  • ‘From’ – function that wraps a value inside the monad – in C#, constructor or static factory
  • ‘Bind’ – function that applies main/core operation within the context of internal computation

Lets try to implement two simple monads:  Maybe (Option) and Writer monad.

Maybe monad’s internal computation checks for ‘null’ values, making top level code path clear of null checks.

Writer monad’s internal computation allows to accumulate additional information as we progress through chain of operations, hiding away explicit logging statements from the top level code path.

Code?

//-- monad interface
//--
public interface IMonad<T> {
//IMonad<T> From(T @value);//note: implemented as constructor
IMonad<T2> Bind<T2>(Func<T, T2> f) where T2 : class;
// simple access the wrapped value(s), optional but helpfull 🙂
string Show();
}
//-- Maybe monad
//--
class MaybeM<T> : IMonad<T> {
internal T _value;
public MaybeM(T value) {
_value = value;
}
public IMonad<T2> Bind<T2>(Func<T, T2> f) where T2 : class {
if (_value != null) {
return new MaybeM<T2>(f(_value));
}
return new MaybeM<T2>(null);
}
public string Show() {
return _value == null ? "null" : _value.ToString();
}
}
//-- Writer monad
//--
class WriterM<T> : IMonad<T> {
internal T _value;
List<string> _info;
public WriterM(T @value) {
_value = value;
_info = new List<string>();
}
WriterM(T @value, List<string> info) {
_value = @value;
_info = info;
}
public IMonad<T2> Bind<T2>(Func<T, T2> f) where T2 : class {
try {
var result = (f(_value));
_info.Add("\{(f.Method).Name}()-> \{result}");
return new WriterM<T2>(f(_value), _info);
}
catch (Exception ex) {
_info.Add("Exception: \{ex.Message} thrown for \{(f.Method).Name}()");
return new WriterM<T2>(default(T2), _info);
}
}
public string Show() {
var valStr = _value.ToString();
_info.ForEach(s => valStr += "\r\n\t" + s);
return valStr;
}
}
view raw maybeM.cs hosted with ❤ by GitHub

and here is how it is used:

static void Main(string[] args) {
//-1) Maybe monad usage: input regular string, intermediate result int...
var maybeM = new MaybeM<string>("I'm a string, wrapped up in the Maybe Monad!");
var result1 = maybeM.Bind(ExtractVowels)
.Bind(Length);
WriteLine("Result is: \{result1.Show()}");
//-2) Maybe monad usage: null string
maybeM = new MaybeM<string>(null);
var result2 = maybeM.Bind(ExtractVowels)
.Bind(Length);
WriteLine("Result is: \{result2.Show()}");
//-3) Writer monad usage
var writerM = new WriterM<string>("I'm a string, wrapped up in the Maybe Monad!");
var result3 = writerM.Bind(ExtractVowels)
.Bind(Length);
WriteLine("Result is: \{result3.Show()}");
ReadLine();
}
view raw MainMaybeM.cs hosted with ❤ by GitHub

You can get full source code by going to this GitHub page. I may continue to play around with this, potentially add other monads and more complex examples of use…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: