0

The quote from Eric's answer: Monads in C# -- why Bind implementations require passed function to return a monad?

"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"

Does that mean that if both g and f return the monad will guarantee that these is a way to go back from the instance the monad to an "unwrapped" type? but how? Can someone explaint this point to me?

Update: Thanks for Aaron and Euge's answers, now I understand that getting back T from M is not part of Monad's requirement (API), but from inside Monad bind function implementation itself, it should know how to get T from M<T>, otherwise, how the Func<T, M<R>> can be called inside the Bind function.

Bowie Can
  • 35
  • 5

2 Answers2

1

No, that is not one of defined properties of a Monad. The Haskell page on Monads explains clearly that you can't directly get an a back out of an M a. The quote is explaining that once you've gone from T to M<T>, you always need to work with M<T>, hence the utility of Lifting.

Aaron M. Eshbach
  • 6,380
  • 12
  • 22
  • Does "Bind" function implicitly mean that it knows to how to get T back from M and produce M? – Bowie Can Jan 05 '18 at 20:22
  • Not necessarily. It may be the case that `bind` is implemented by unwrapping `M ` to `T` before mapping from `T -> M`, but alternatively, it may lift the `T -> M` to `M -> M` and then apply that to `M` directly. – Aaron M. Eshbach Jan 05 '18 at 20:33
0

As Aaron already said, the answer is no. The simplest example to see that you cannot always "come back" from a monad, in my opinion, is the case of the frequently called Maybe monad or Option. You can see an implementation in C# here: https://mikhail.io/2016/01/monads-explained-in-csharp/

I don't really know C# so I will avoid writing code and try to explain it with words.

To model computations that can fail we could use a data type that either is a value or it is nothing (think of an alternative to null). The requirements for that datatype to be a monad are the following:

  • If we have a computation that never fails, returning something of type B, then we can get an equivelent computation that returns Maybe<B>. This is the return constructor, that simply wraps the value inside Maybe.
  • We can compose computations that might fail. How? Well, if the first one fails, everything fails. If it doesn't, then we pass the returned value to the next function. This is the behaviour of bind.
  • We also need some laws to be valid, but let's forget about it for the sake of simplicity.

Consider the case where we compose two functions that might fail. Can we always get a value? Well, not always. We get a value when neither of the two functions have failed.

I will try to explain it with code now. You can correct me when I'm wrong. So lets say we have maybe a value maybeValue of type A

Maybe<A> maybeValue = ...;

And we have a function foo that takes values of type A.

Maybe<B> foo(A a) {...}

We want to pass maybeValue to foo. Monads let you do that without inspecting maybeValue to see if it has or not a value. Yo do it like this:

Maybe<B> result = maybeValue.bind(foo)

Again: Can I always transform result into something of type B? I mean, does result always contain a value? Well, no. Only when both maybeValue and foo were successful.

Euge
  • 699
  • 10
  • 14
  • but Maybe's implementation from https://mikhail.io/2016/01/monads-explained-in-csharp/, it knows how to get the T from Maybe – Bowie Can Jan 07 '18 at 16:09
  • I dont see a method that gets a `T` out of a `Maybe`. It can't be done for the `None` object case. – Euge Jan 07 '18 at 17:21