Monads in C#: Which Part Is The Monad?
In my previous post on refactoring some code, several people responded in the comments and via twitter that I should look at the Maybe
Given all that, I’ve been doing some r&d to learn how to implement my own monadic method chaining goodness, and I’ve come to a point where I’m not actually sure which parts of the code are the monads and which parts are implementation details that are side effects of doing this in C#. I’m hoping you, dear reader, can help me understand this. I’m writing this blog post as a learning tool for myself – not only to ask questions, but also to see what I can learn by solidifying my knowledge into a concrete form: this blog post.
Implementing Maybe
Based on several articles and blog posts that I’ve read, I decided to implement the canonical Maybe
1: public sealed class Maybe<T>
2: {
3: public static Maybe<T> None = new Maybe<T>(default(T));
4:
5: private T value;
6: public T Value
7: {
8: get
9: {
10: return value;
11: }
12: set { this.value = value; }
13: }
14:
15: public bool HasValue
16: {
17: get
18: {
19: bool hasValue = false;
20: if (Value != null && !Value.Equals(default(T)))
21: hasValue = true;
22: return hasValue;
23: }
24: }
25:
26: public Maybe(T value)
27: {
28: Value = value;
29: }
30: }
</div> </div>
This allows me to check whether I have a value or not, and get that value when I want to. (Note that I did not use the built in Nullable
Next, I implemented several extension methods that I found via this article by Dmitri Nesteruk.
</div> </div>
And lastly, I put together a sample that uses these methods:
</div> </div>
In this example, if any of the method calls or funcs returns a null, I will end up with “nothing here. move along” as the text written to my console. However, if none of them produces a null value, then I will end up retrieving the Baz.Name property from my object graph (which looks like: Foo, Foo.Bar, Bar.Baz, Baz.Name).
Now that I have this in place, I find myself asking… which part of this is the actual monad? According to Wikipedia, a monad:
is a kind of abstract data type constructor used to represent computations (instead of data in the domain model). Monads allow the programmer to chain actions together to build a pipeline, in which each action is decorated with additional processing rules provided by the monad. Programs written in functional style can make use of monads to structure procedures that include sequenced operations, or to define arbitrary control flows (like handling concurrency, continuations, or exceptions).
Formally, a monad is constructed by defining two operations (bind and return) and a type constructor M that must fulfill several properties to allow the correct composition of monadic functions (i.e. functions that use values from the monad as their arguments). The return operation takes a value from a plain type and puts it into a monadic container of type M. The bind operation performs the reverse process, extracting the original value from the container and passing it to the associated next function in the pipeline.
A programmer will compose monadic functions to define a data-processing pipeline. The monad acts as a framework, as it’s a reusable behavior that decides the order in which the specific monadic functions in the pipeline are called, and manages all the undercover work required by the computation. The bind and return operators interleaved in the pipeline will be executed after each monadic function returns control, and will take care of the particular aspects handled by the monad.
When I first read this, I got lost… very lost. So I started reading other articles by other developers. However, it wasn’t until I had actually implemented the Maybe
When I first started reading the Maybe
The third paragraph in the above text begins to give me a better picture, I think. “A programmer will compose monadic functions to define a data-processing pipeline.” Aha! Perhaps it is the actual extension methods that are the monads? Or at least, these are the monadic function that this paragraph refers to. But I don’t think that the extension methods are themselves the monad because the paragraph goes on to talk about the monad being a framework in which monadic functions are chained together. It also says the monad itself manages the order of execution. So then the monad isn’t the individual methods.
I’m starting to get the feeling that a monad implemented in C# is more of a concept or aggregation of ideas and implementation detail, than an explicit construct. Given everything that the wikipedia article says, given all the examples I’ve looked at, and given the example that I show above, I think the actual monad is the aggregation of the extension methods, the Maybe
</div> </div>
This code represents is the pipeline of monadic functions, put together in the specific order that they will be called, using the monadic extension methods that I created around the Maybe
If a monad in C# is more of a concept – more like a design pattern where the intention is critical in determining which specific pattern was used – then this would also reconcile my questioning of Dmitri’s article. It’s not the individual methods that are the monad – it’s the pipelined execution and examples that he gives that are the actual monad. In his article, for example, he shows this code:
</div> </div>
This is the monad, itself, just like my code right above it is the monad. In Dmitri’s example and methods, he is not using a generics class to Return and Bind as my example does. Rather, he is allowing the language to implicitly Return and Bind.
When the With method is called in Dmitri’s code, this is implicitly the first Return of the monad; not because the With method itself is the Return, but because this is the first part of the monad and the value is being wrapped into a type that the monadic functions can understand. It just happens to be, in this case, that the monadic functions can take any type through the use of generics in C#. In my example code, the .ToMaybe() method is the explicit Return portion of the monad. I am explicitly wrapping the value in a type that my monadic extension methods can use.
(Note: don’t confuse the “Return” method at the end of the pipeline with the “Return” concept of a monad. They aren’t the same. The Return method is just a poorly named method in this case, because it muddies the waters and makes it seem like this is the Return concept in the monad.)
The Bind occurs every time a monadic function is called. In Dmitri’s code, Bind is again implicit. Because the generics type system in C# allows us to pass any type we want, we don’t have to explicitly Bind the value to the method calls. We can simply pass them along. In my example code, though, I am explicitly doing the Bind when I retrieve the .Value and pass it into the func delegate: func(maybe.Value). This is the Bind portion.
After the Bind occurs, we once again Return the wrapped value. Again, Dmitri’s code does this implicitly with generics and I do it explicitly with my Maybe
How am I doing, here? How close am I? How far off? What detail am I missing? I’m still trying to get my head completely wrapped around all of this and I really want to some additional expert opinion weighed in on this. Please, please PLEASE let me know where I’ve gone wrong and what I need to do to correct my understanding! Everything I’ve said so far seems to make sense to me, so far. I hope it makes sense to the experts and to the people that are trying to learn this stuff, too.
Here’s the articles and blog posts that I’ve looked at, so far, that have helped me in my journey. Hopefully this will help others, as well.
If anyone else has other great resources and links on Monads in .NET (especially monads in C#), please post them in the comments here or in your own blog with a link back to this post.
1: public static class MaybeExtensions
2: {
3: public static Maybe<T> ToMaybe<T>(this T input)
4: {
5: return new Maybe<T>(input);
6: }
7:
8: public static Maybe<TResult> Get<TInput, TResult>(this Maybe<TInput> maybe, Func<TInput, TResult> func)
9: {
10: Maybe<TResult> result;
11: if (maybe.HasValue)
12: result = new Maybe<TResult>(func(maybe.Value));
13: else
14: result = Maybe<TResult>.None;
15: return result;
16: }
17:
18: public static Maybe<TInput> If<TInput>(this Maybe<TInput> maybe, Func<TInput, bool> func)
19: {
20: Maybe<TInput> result;
21: if (maybe.HasValue && func(maybe.Value))
22: result = maybe;
23: else
24: result = Maybe<TInput>.None;
25: return result;
26: }
27:
28: public static TResult Return<TInput, TResult>(this Maybe<TInput> maybe, Func<TInput, TResult> func, TResult defaultValue)
29: {
30: TResult result = defaultValue;
31: if (maybe.HasValue)
32: result = func(maybe.Value);
33: return result;
34: }
35: }
1: var foo = new Foo();
2:
3: var output = foo.ToMaybe()
4: .Get(SomeMethodToRetrieveABar)
5: .If(CheckSomethingComplexWithBarHere)
6: .Get(r => r.Baz)
7: .Return(z => z.Name, "nothing here. move along");
8:
9: Console.WriteLine(output);
A Long, Confusing Definition Of Monad
Return And Bind
Monadic Functions
Are Monads In C# A Concept More Than A Construct?
1: var output = foo.ToMaybe()
2: .Get(SomeMethodToRetrieveABar)
3: .If(CheckSomethingComplexWithBarHere)
4: .Get(r => r.Baz)
5: .Return(z => z.Name, "nothing here. move along");
Return And Bind, Again
1: string postCode = this.With(x => person)
2: .If(x => HasMedicalRecord(x))]
3: .With(x => x.Address)
4: .Do(x => CheckAddress(x))
5: .With(x => x.PostCode)
6: .Return(x => x.ToString(), "UNKNOWN");
Will The Real Monad Please Stand Up?
Resources On Monads In .NET