17

Most examples of monads I saw in C# are written somewhat like that:

public static Identity<B> Bind<A, B>(this Identity<A> a, Func<A, Identity<B>> func) {
    return func(a.Value);
}

For example, see http://mikehadlow.blogspot.com/2011/01/monads-in-c-3-creating-our-first-monad.html.

The question is, what is the point of requiring func to return an Identity<B> ? If I use the following definition:

public interface IValue<A> {
    public IValue<B> Bind<B>(Func<A, B> func)
}

then I can actually use same func for for Lazy<T>, Task<T>, Maybe<T> etc without actually depending on actual type implementing IValue.

Is there something important I am missing here?

Andrey Shchekin
  • 21,101
  • 19
  • 94
  • 162
  • Could you provide a link to the example? – Eric Andres Oct 19 '11 at 21:52
  • The first one? It is from http://mikehadlow.blogspot.com/2011/01/monads-in-c-3-creating-our-first-monad.html. Added that link to the original question. – Andrey Shchekin Oct 19 '11 at 22:12
  • 1
    The `Bind` you define in `IValue` is actually a `map` or `lift` function (in C# usually called `Select`) – Mauricio Scheffer Oct 19 '11 at 22:54
  • So only thing `Bind` adds over `Lift` is a 'flattening' in the case where function does actually return a monad of the same type? – Andrey Shchekin Oct 19 '11 at 23:39
  • 1
    'flattening' is one way to see it (in Scala bind is called `flatMap`), but think of a `Maybe` monad: with `map` alone you can't go from "something with a value" to "no value" so you wouldn't be able to break the computation. – Mauricio Scheffer Oct 20 '11 at 00:07
  • I see, yes. I think you should make your comment an answer since while Eric's response is great, I think it does not completely address my question of composing functions `T => Monad` and `U => V`. – Andrey Shchekin Oct 20 '11 at 00:51
  • This raises another question -- what is the benefit of having separate `bind` and `lift` in C# where you can easily pass `Func` that actually returns `Maybe` to `Maybe.lift` instead of `Maybe.bind`. Should `lift` in such a language just cast the result to see whether it should manage it specially? Well, you would not be able to create lists of lists if `Select` just flattened any lists it received from selector func, but it looks like an edge case. Ok, maybe it should be a separate question. – Andrey Shchekin Oct 20 '11 at 00:55
  • Indeed `lift` for a monad can be seen as a convenience function (i.e. non-essential) since it can be expressed in terms of `bind` and `return` (see http://hackage.haskell.org/packages/archive/base/latest/doc/html/src/Control-Monad.html#liftM ). A *very* convenient function. – Mauricio Scheffer Oct 20 '11 at 01:08
  • @MauricioScheffer can you create an answer from your comment about lift? It is enough information for me to accept it for this question. – Andrey Shchekin Oct 20 '11 at 02:14

1 Answers1

34

First off, consider the notion of composition. We can express composition as an operation on delegates easily:

public static Func<T, V> Compose<T, U, V>(this Func<U, V> f, Func<T, U> g)
{
    return x => f(g(x));
}

So if I have a function g which is (int x) => x.ToString() and a function f which is (string s) => s.Length then I can make a composed function h which is (int x) => x.ToString().Length by calling f.Compose(g).

That should be clear.

Now suppose I have a function g from T to Monad<U> and a function f from U to Monad<V>. I wish to write a method that composes these two functions that return monads into a function that takes a T and returns a Monad<V>. So I try to write that:

public static Func<T, Monad<V>> Compose<T, U, V>(this Func<U, Monad<V>> f, Func<T, Monad<U>> g)
{
    return x => f(g(x));
}

Doesn't work. g returns a Monad<U> but f takes a U. I have a way to "wrap" a U into a Monad<U> but I don't have a way to "unwrap" one.

However, if I have a method

public static Monad<V> Bind<U, V>(this Monad<U> m, Func<U, Monad<V>> k)
{ whatever }

then I can write a method that composes two methods that both return monads:

public static Func<T, Monad<V>> Compose<T, U, V>(this Func<U, Monad<V>> f, Func<T, Monad<U>> g)
{
    return x => Bind(g(x), f);
}

That's why Bind takes a func from T to Monad<U> -- because the whole point of the thing is to be able to take a function g from T to Monad<U> and a function f from U to Monad<V> and compose them into a function h from T to Monad<V>.

If you want to take a function g from T to U and a function f from U to Monad<V> then you don't need Bind in the first place. Just compose the functions normally to get a method from T to Monad<V>! The whole purpose of Bind is to solve this problem; if you wave that problem away then you don't need Bind in the first place.

UPDATE:

In most cases I want to compose function g from T to Monad<U> and function f from U to V.

And I presume you then want to compose that into a function from T to V. But you can't guarantee that such an operation is defined! For example, take the "Maybe monad" as the monad, which is expressed in C# as T?. Suppose you have g as (int x)=>(double?)null and you have a function f that is (double y)=>(decimal)y. How are you supposed to compose f and g into a method that takes an int and returns the non-nullable decimal type? There is no "unwrapping" that unwraps the nullable double into a double value that f can take!

You can use Bind to compose f and g into a method that takes an int and returns a nullable decimal:

public static Func<T, Monad<V>> Compose<T, U, V>(this Func<U, V> f, Func<T, Monad<U>> g)
{
    return x => Bind(g(x), x=>Unit(f(x)));
}

where Unit is a function that takes a V and returns a Monad<V>.

But there simply is no composition of f and g if g returns a monad and f doesn't return the monad -- there is no guarantee that there is a way to go back from the instance of the monad to an "unwrapped" type. Maybe in the case of some monads there always is -- like Lazy<T>. Or maybe there sometimes is, like with the "maybe" monad. There often is a way to do it, but there is not a requirement that you can do so.

Incidentally, notice how we just used "Bind" as a Swiss Army Knife to make a new kind of composition. Bind can make any operation! For example, suppose we have the Bind operation on the sequence monad, which we call "SelectMany" on the IEnumerable<T> type in C#:

static IEnumerable<V> SelectMany<U, V>(this IEnumerable<U> sequence, Func<U, IEnumerable<V>> f)
{
    foreach(U u in sequence)
        foreach(V v in f(u))
            yield return v;
}

You might also have an operator on sequences:

static IEnumerable<A> Where<A>(this IEnumerable<A> sequence, Func<A, bool> predicate)
{
    foreach(A item in sequence)
        if (predicate(item)) 
            yield return item;
}

Do you really need to write that code inside Where? No! You can instead build it entirely out of "Bind/SelectMany":

static IEnumerable<A> Where<A>(this IEnumerable<A> sequence, Func<A, bool> predicate)
{
    return sequence.SelectMany((A a)=>predicate(a) ? new A[] { a } : new A[] { } );  
}

Efficient? No. But there is nothing that Bind/SelectMany cannot do. If you really wanted to you could build all of the LINQ sequence operators out of nothing but SelectMany.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Thanks a lot for your response, however I still have a question. In most cases I want to compose function g from `T` to `Monad` and function f from `U` to `V`. For example, I want to add `5` to `Lazy`, so `5+()` is a function f from `int` to `int`, but I have a `Monad` (Lazy, from some previous function call). So the unwrapping case is still relevant, but why would I want `5+()` function to return a monad? Why can't I do both unwrapping and re-wrapping within a `Bind` function? – Andrey Shchekin Oct 19 '11 at 22:42
  • @AndreyShchekin The point is that the `Bind` operation is not designed to (only) solve the kind of problem you just described. To put it another way, `Bind` is overkill for that sort of problem. – Daniel Pratt Oct 19 '11 at 23:15
  • @DanielPratt but what is designed for this problem? Functions in my case can not just be composed directly, because I need to understand how to apply a given operation to an internal value of the monad. – Andrey Shchekin Oct 19 '11 at 23:28
  • 1
    Someone already mentioned this in a comment to your question, but it appears you are looking for an operation that is generally called `map`. The .NET framework calls it `Select`. Take a look at the type of the `Enumerable.Select` method: http://msdn.microsoft.com/en-us/library/bb548891.aspx It has pretty much the type you gave to `Bind` in your question. – Daniel Pratt Oct 19 '11 at 23:33
  • I see, so the question should have been 'why monads use `bind` instead of `lift`', but that's probably to allow flattening. – Andrey Shchekin Oct 19 '11 at 23:40
  • 1
    @AndreyShchekin: I've updated my answer to respond to your second question. – Eric Lippert Oct 20 '11 at 04:31
  • @EricLippert thanks a lot, I still have some questions, but they are pretty far away from the original one, so I'll ask them separately. – Andrey Shchekin Oct 20 '11 at 22:42