1

I'm just trying to get monads, so bear with me if I ask a bad question, but...

If monads only require:

  • (a -> M a), where M is the monadic type constructor, and
  • (M a -> (a -> M b) -> M b), which is the bind operation (which I understand as mapping a monad onto a non-monadic to monadic value function)

...doesn't this mean that:

  • (M a -> a) and
  • (M (M a) -> M a) are not implicitly required?

Won't this usually cause a problem?

  • Suppose we have a set of functions, S, which all have the type (x -> y), where x and y are arbitrary types.

  • Now, suppose I program using a set of monadic functions M, where their types are x -> M y.

Doesn't this mean that once I turn a type into M y, I can't use any of the (x -> y) functions? Or, can I assume that I can do (M x -> (x -> y) -> (y -> M y) -> M y)?

Furthermore, don't we usually want to extract the original type when programming? When switching between something, like async a -> a or maybe a -> a... Isn't that a common operation? I can definitely see the case where somebody wants to optimize a monad out if they see it as negligible (e.g. a logging monad).

Additionally, what about layered monads without flattening? I understand that lists can be seen as monads where restricting flattening is a clear and logical choice, but what about the hypothetical case of async (async a) monadic values where async has no flatten function? Does bind only imply one layer of "monadic reduction" where we can often assume that (M a -> (a -> M a) -> M a) can often be seen as (M a -> (M a -> a) -> (a -> M a) -> M a), and (M M a -> (a -> M a) -> M a or M M a) may not work? Is there a true difference between flattening and non-flattening monads?

CinchBlue
  • 6,046
  • 1
  • 27
  • 58
  • This question might be better posted on http://cstheory.stackexchange.com/ instead of here. Stack Overflow is more about practical programming issues. – Enigmativity Jan 08 '16 at 09:46
  • 1
    `M a -> a` is not required. Not all monads need to support it. `M (M a) -> M a` can be derived from `return` and `bind` (which is `M a -> (a -> M b) -> M b` BTW). – n. m. could be an AI Jan 08 '16 at 18:34
  • @n.m. So that means I *can't* use the set of functions S of type `(a -> b)`? If I need to induct my entire set of functions into the set of monadic functions, wouldn't that mean I either have to manually convert each `(a -> b) -> (a -> M b)` by applying a monadic constructor somewhere? – CinchBlue Jan 08 '16 at 19:39
  • I'm trying to talk about two things: 1) monadic values that can't be unpacked to be compatible with functions that don't deal with them at all in input or output and 2) layered monads that have a way to become incompatible with the monadic type system *if we don't apply flatten.* If monads don't require flatten, then it doesn't matter if I can implement flatten in terms of bind. For example, a `List(List(a))` can be flattened, but since there's no one way to flatten a list, does this mean that the List monad is special? If so, doesn't this mean that flattening and non-flattening monads differ? – CinchBlue Jan 08 '16 at 19:44
  • 1
    If you have ever written a Haskell program that does IO, you know you don't have to manually convert every single function to `a->IO b`,. – n. m. could be an AI Jan 08 '16 at 19:45
  • 1
    You can define any monad in terms of `bind` or in terms of `flatten`. These two ways are equivalent. If you have `bind`, you can define `flatten` in terms of `bind`, and vice versa. – n. m. could be an AI Jan 08 '16 at 19:56
  • @n.m. "You can define any monad in terms of bind or in terms of flatten." You can, but you aren't required by definition. However, if we use the other definition of it being a subclass of Applicative in Haskell or Functors, the join becomes implicit to definition. With just bind and return, we need to construct join if we want it. It doesn't come with the definition by default. – CinchBlue Jan 08 '16 at 20:52
  • `join m = m >>= id`. Here, constructed. – n. m. could be an AI Jan 08 '16 at 21:22

1 Answers1

1

Won't this usually cause a problem?

You might say that this is "by design". One of the possible uses is IO; once you have a value tainted with IO, you have to "bubble up"; you can't hide the fact that a function is doing IO under a pure value.


wouldn't that mean I either have to manually convert each (a -> b) -> (a -> M b) by applying a monadic constructor somewhere?

This is easier than you think because every Monad is also a Functor and an Applicative Functor:

randomDice :: IO Int
randomDice = randomRIO (1,6)

cheat :: Int -> Int
cheat = (+1)

main = do
    dice <- randomDice
    dice' <- cheat <$> randomDice

Having all of the fmap, <$>, liftA/liftM and pure/return machinery at our disposal, it makes it very simple to easily use pure functions in the monadic contexts.


(M (M a) -> M a) is not implicitly required

That one is false. You only need bind to implement it.

join              :: (Monad m) => m (m a) -> m a
join x            =  x >>= id
Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
  • http://stackoverflow.com/questions/10342876/differences-between-functors-and-endofunctors --- `join` seemed to be required, but here, it states it can be constructed from the two. But can !== is, so wouldn't a {bind, return} be something different than {bind, return, join}? – CinchBlue Jan 08 '16 at 20:50
  • @VermillionAzure the latter just has redundancy in it. – Bartek Banachewicz Jan 08 '16 at 20:54
  • The difference I'm trying to make is that of equivalence vs. subset. An integer *can* be a floating point number, but isn't in of itself. It can be implicitly constructed with a cast. Likewise, a typeclass of {bind, return} has a subclass {bind, return, join} with an additional implementation, but the two aren't the same by definition. It's like saying how all computer logic can be constructed from NAND gates but everything is not NAND. Does this make more sense? – CinchBlue Jan 08 '16 at 20:57
  • @VermillionAzure No, there is no subclass. `bind`, `return` and `join` must abide monad laws, which state that the equation `join x = x >>= id` holds. – n. m. could be an AI Jan 08 '16 at 21:26