2

I remember that monad is a monoid. That is, there is an associative binary operation * so that if ma and mb are monadic values then ma * mb is a monadic value too.

If the above is correct, what is that binary operation for Option in Scala ? For example, what can be * in Some(1) * Some(2) ?

Michael
  • 41,026
  • 70
  • 193
  • 341
  • What do you mean on `ma` and `mb`? For instance `Option(1)` and `Option(2)`? – senia Feb 17 '14 at 11:30
  • Why? Isn't `append` a binary associative operation? What is `Some(z)` append {`Some(x)` append `Some(y)`}? Is that the same if you change order? – S.R.I Feb 17 '14 at 11:39
  • @senia Yes (updated the question), I mean something like `Some(1) * Some(2)`. What is `*` here ? – Michael Feb 17 '14 at 12:26
  • 2
    The question is: Do you really want to know…? http://stackoverflow.com/a/3870310/200266 (Answer: `*` == `join`/`flatten`; **1** == `return`.) – Debilski Feb 17 '14 at 12:34
  • @Debilski Could you please elaborate a bit and maybe give a full answer? – Michael Feb 17 '14 at 13:09

5 Answers5

4

I think orElse is a valid associative binary operator:

def test(a: Option[Int], b: Option[Int], c: Option[Int]): Boolean =
  ((a orElse b) orElse c) == (a orElse (b orElse c))

Seq(Option(1), Option(2), None).permutations.forall {
  case Seq(a, b, c) => test(a, b, c)
}

This holds. I have used this property in a FingerTree implementation, it was proposed by Hinze & Paterson in their Haskell version, it is used to implement an interval tree.

0__
  • 66,707
  • 21
  • 171
  • 266
  • Thanks. And what is the _identity_ for this operation ? – Michael Feb 17 '14 at 12:30
  • @Michael: `None orElse b` == `b orElse None` == `b`. – senia Feb 17 '14 at 12:33
  • 2
    @Michael: The identity element in this would be `None`. `None orElse Some(3) == Some(3) == Some(3) orElse None`. This is no answer however to the question how *every* monad is also a monoid. – Debilski Feb 17 '14 at 12:33
4

(This answer stole its definitions from https://stackoverflow.com/a/3870310/200266 and only tries to give a rough explanation. My knowledge of category theory is rather basic.)

In the generic case, saying that a monad is also a monoid is only valid, if you consider the functor (eg. T => Option[T]) and not the values (eg. Some(3) or None).

As an example for a monoid over values, let’s have a look at List[T].

We have a binary operation • : S × S -> S:

def append[T](list1: List[T], list2: List[T]): List[T] = list1 append list2

and the empty list Nil is obviously the identity element. There is no append method in every monad, though, so the above cannot be generalised onto all monads. Let’s change the definition of the binary operation a bit.

Now, in the above case × can be seen as returning a tuple of the input values:

List[T] × List[T] => (List[T], List[T])

And our append function receives this tuple as its input.

However, we may change the tupling operation × to , now meaning functor composition.

(K => List[K]) ∘ (K => List[K]) => (K => List[List[K]])

And so, we’re looking for a function fulfilling μ : T ∘ T -> T or more specific

(K => List[List[K]]) => (K => List[K])

That operation is known in Scala as flatten (join in Haskell). The monoid’s identity element is the the monad constructor which has no generic name in Scala (return in Haskell), but which exists for every monad. Eg. x => List(x).

To wrap things up, considering this and the other answers in this question, there are three possibilities for how a monad can be a monoid:

A) Every monad is also a monoid in the above sense under functor composition.

B) Every monad M[T] has a monoid if there is also a monoid (with some binary operation ~+~) for T: for {x <- ma; y <- mb} yield x ~+~ y

C) Some monads may have one or more specific monoids which differs from the one in B. For example List’s append or Option’s orElse.

Community
  • 1
  • 1
Debilski
  • 66,976
  • 12
  • 110
  • 133
3

An Option by itself is not a monoid just like an Integer is not a monoid by itself. A monoid is a type AND the associative binary operation.

You can consider the Integer type AND addition a monoid. Integer and multiplication are a monoid too. Turning two Integers to String and concatenating them ("2" + "3" = "23") is a valid associative operation too that could create a monoid with Integers: in fact ("2" concat "3") concat "4" = "2" concat ("3" concat "4") = "234".

The thing is, it's up to you to define the associative operation that completes the definition of "monoid" for a type, so your question "what is THE associative operation...." is not well-formed.

As with Integers, Option[Int] and addition or multiplications can be monoids, but an Option[Int] per se is not.

Like @senia does in his answer you can say "I can define a monoid based on Option[T] if T is itself a Monoid". In that case, the associative operation can use the one that was defined for T and Some[a] append Some[b] can be Some[a append b].

Or, as @0__ did, you can find a particular operation (orElse) that, together with Option[Int] makes a monoid. That is correct too (but notice how the answer starts with "orElse is a valid associative binary operator").

Paolo Falabella
  • 24,914
  • 3
  • 72
  • 86
2

Actually not. Monad for Option is not a Monoid for Option[T]. Monad is defined for M[_] and Monoid is defined for T.

You can create Monoid for Option[T] if you have Monoid for T like this:

def optionMonoid[T: Monoid]: Monoid[Option[T]] = new Monoid {
  def zero: Option[T] = None
  def append(f1: Option[T], f2: => Option[T]): Option[T] = (fi, f2) match {
    case (None, None) => None
    case (Some(a), Some(b)) => Some(a |+| b)
    case (r @ Some(_), None) => r
    case (None, r @ Some(_)) => r
  }
}
senia
  • 37,745
  • 4
  • 88
  • 129
  • 2
    "`Monad` is not a `Monoid`". [Well, actually...](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html) – Travis Brown Feb 17 '14 at 11:20
  • @TravisBrown: I've tried to express this in `scala` as `def monadIsMonoid[...: Monad]: Monoid[...]` and it looks like it's impossible. Is there a programming language where one can express this idea in code? – senia Feb 17 '14 at 12:37
  • Wrong monoid; see my answer. – Alexey Romanov Feb 17 '14 at 14:00
  • @senia: Sorry, meant mostly as a joke, but you can do it if you have [kind polymorphism](http://www.jonmsterling.com/posts/2012-01-12-unifying-monoids-and-monads-with-polymorphic-kinds.html). – Travis Brown Feb 17 '14 at 20:00
2

There are two different senses of monoid. A monad is a monoid object in the category theory sense (see the last example there); it isn't a monoid in the abstract algebra sense (which most other answers are talking about).

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487