I am trying to grok get a preliminary understanding of monads.
I have a data layer call whose result I would like to return monadically either as a result eg no of rows updated/dataset etc, or an exception. I figure I need to use the Exception monad which I could see as a special case of the Either monad
I've looked round at various samples - tonnes of Maybe samples, and I am not quite sure how or if to generalise this to become an Either monad - but I can't find any which are not in haskell - and, unfortunately, I most certainly don't grok haskell!
I was wondering if anyone could point me to any samples.
We have implemented
Either
data structure in our C# solution and we are happy using it. Here is the most simple version of such implementation:(our code has more helper methods, but they are optional)
The main points are
Left
orRight
I've also described how we use this Either type for data validation.
It's worth noting that there are C# libraries available now that contain implementations of
Either
:language-ext library is available for .Net 4.5.1 and .Net Standard 1.3
LaYumba library is available for .Net Standard 1.6 and .Net Core 1.1.
Both libraries are well documented, with LaYumba being used as the basis of the Manning book Functional Programming in C#.
C# doesn't have much support for monads (and the support that is there in the form of LINQ wasn't really meant for general monads), there are no built-in Exception or Either monads. You should
throw
the exception and thencatch
it.While learning a bit about monads in C#, for exercise I implemented an
Exceptional
monad for myself. With this monad, you can chain up operations that might throw anException
like in these 2 examples:Both expressions yield the same result, just the syntax is different. The result will be an
Exceptional<T>
with the arisenDivideByZeroException
set as property. The first example shows the "core" of the monad using LINQ, the second contains a different and perhaps more readable syntax, which illustrates the method chaining in a more understandable way.So, how it's implemented? Here's the
Exceptional<T>
type:The monad is completed through extension methods
ToExceptional<T>()
andSelectMany<T, U>()
, that correspond to the monad's Unit and Bind functions:And some little helper structures, that are not part of the monad's core:
Some explanation: a method chain built with this monad is executed as long as one method of the chain throws an exception. In this case no more method of the chain will be executed and the first thrown exception will be returned as part of an
Exceptional<T>
result. In this case theHasException
andException
properties will be set. If noException
occurs,HasException
will befalse
and theValue
property will be set, containing the result of the executed method chain.Note that the
Exceptional<T>(Func<T> getValue)
constructor is responsible for the exception handling and theSelectMany<T,U>()
method is responsible for distinguishing if a method, that was executed before, has thrown an exception.So - don't know if anyone is interested - I've come up with a very preliminary implementation very much following Mike Hadlow's lead. Some of it doesn't feel quite right atm but it is a start. (Having said that, I wouldn't use it - you might lose a million dollars or even kill someone - just my caveat!)
A very simple sample of the kind of code that could be written is
with the Div method implemented as follows:
or
(Straight away I can see an potential improvement to the api but am unsure quite how to achieve it. I think that this
would be nicer if it were
You'll see my implementation later and hopefully someone will be able to re-architect it for the above.)
The monadic bit is done in here (mainly)
The main interface is specified as
and I have an internal interface I use to get at the exception which has been thrown (more later)
The concrete implementations are as follows:
Just a word of explanation ... the trickiest bit, for me, was the Bind operation when an exception has arisen. If you are dealing with a pipeline of operations and an exception gets thrown early on in the process, you need to perpetuate that exception down the pipeline so that when the expression completes the returning IExceptional contains the exception which occurred earlier. This is the reason for the IInternalException. It enables me to create a new IExceptional of the same or (potentially different) type (eg IExceptional --> IExceptional) but copies across the exception to the new IExceptional without me having to know the type of the internal exception.
No doubt there are loads of improvements possible. eg I could see that you may potentially want to keep track of the error stack within the IExceptional. There is probably redundant code or better ways to achieve the ends ... but ... it was meant to be a bit of learning for me.
Any thoughts/suggestions would be gratefully received.