We are closing in on the actual requirements of the “monad pattern”. So far we’ve seen that for a monadic type M<T>, there must be a simple way to “wrap up” any value of T into an M<T>. And last time we saw that any function that takes an A and returns an R can be applied to an M<A> to produce an M<R> such that both the action of the function and the “amplification” of the monad are preserved, which is pretty cool. It looks like we’re done; what more could you possibly want?
Well, let me throw a spanner into the works here and we’ll see what grinds to a halt. I said that you can take any one-parameter function that has any non-void return type whatsoever, and apply that function to a monad to produce an M<R> for the return type. Any return type whatsoever, eh? OK then. Suppose we have this function of one parameter:
(Again, for expository purposes I am writing the code far less concisely than I normally would, and of course we are ignoring the fact that double already has a “null” value, NaN.)
static Nullable<double> SafeLog(int x)
{
if (x > 0)
return new Nullable<double>(Math.Log(x));
else
return new Nullable<double>();
}
Seems like a pretty reasonable function of one parameter. This means that we should be able to apply that function to a Nullable<int> and get back out…
oh dear.
Continue reading →