2

So a very very common pattern in Scala is a for comprehension as follows:

for {
  i <- monadA
  j <- monadB
} yield (i, j)

Similarly for 3-tuples, ..., n-tuples. This is becoming so common in my code I'd imagine that scalaz provide some awesome operator to do this for me, e.g. monadA funnyOperator monadB funnyOperator monadC. I've looked around and can't seem to find anything. So I've defined my own implicit class for 2-tuples and 3-tuples but would prefer to use scalaz.

Bonus

In response the currently accepted answer, would love to see someone tell how to make this compile:

import scalaz.Scalaz._

// Like a 1 element list
case class MyMonad[+T](x: T) {
  def map[U](f: T => U): MyMonad[U] = MyMonad(f(x))
  def flatMap[U](f: T => MyMonad[U]): MyMonad[U] = f(x)
}

val myMonad: MyMonad[(Int, Int)] = (MyMonad(1) |@| MyMonad(2)).tupled

and not give:

error: value |@| is not a member of MyMonad[Int]

Bonus Solution:

You need to "provide an applicative instance" e.g.

implicit def myMonadApplicative: Bind[MyMonad] = new Bind[MyMonad] {
  def bind[A, B](fa: MyMonad[A])(f: A => MyMonad[B]): MyMonad[B] = fa.flatMap(f)
  def map[A, B](fa: MyMonad[A])(f: A => B): MyMonad[B] = fa.map(f)
}
samthebest
  • 30,803
  • 25
  • 102
  • 142
  • possible duplicate of [Converting a tuple of options to an option of tuple with Scalaz or Shapeless](http://stackoverflow.com/questions/12408086/converting-a-tuple-of-options-to-an-option-of-tuple-with-scalaz-or-shapeless) – Gabriele Petronella Jan 14 '15 at 14:21
  • It's not a duplicate, I'm specifically looking for a syntactic sugar associated with all Monads. The linked question asks how to basically do a for-comprehension with Options. – samthebest Jan 14 '15 at 14:47
  • The answers still apply. Despite the question, there's nothing specific to `Option` there. – Gabriele Petronella Jan 14 '15 at 14:48
  • Well I did a `CMD + F` for `|@|` and it wasn't there, nor any other kind of operator which is what I asked for. – samthebest Jan 14 '15 at 15:02
  • The fact that another answer exists, doesn't mean the problem is not the same – Gabriele Petronella Jan 14 '15 at 15:03
  • I'm specifically looking for a syntactic sugar associated with all Monads. I'm specifically looking for an *operator*. The linked question just asks *how*, **I'm specifically looking for "an awesome operator"**. @GabrielePetronella The other question does not ask for this. Therefore the questions are different. Now please remove your close vote :) – samthebest Jan 14 '15 at 15:10
  • The other question is specific, but the problem is very much general, and all the answers address the problem generically for any `Applicative` (nothing specific to `Option` in any of them). What you care about are the answers, ultimately, so read them. – Gabriele Petronella Jan 14 '15 at 15:12
  • @GabrielePetronella I'm specifically looking for a syntactic sugar associated with all Monads. I'm specifically looking for an operator. Neither the question nor the answers provide such an operator. I feel like we are going round in circles, how many times do I have to say *I'm looking for an operator* before you acknowledge I'm looking for an operator???? – samthebest Jan 14 '15 at 15:19

2 Answers2

4

Given that each Monad is an Applicative you can also use

(monadA |@| monadB).tupled

E.g.

scala> val b: List[(Int, Int)] = (List(1, 2, 3) |@| List(4, 6)).tupled
b: List[(Int, Int)] = List((1,4), (1,6), (2,4), (2,6), (3,4), (3,6))
samthebest
  • 30,803
  • 25
  • 102
  • 142
gruggie
  • 436
  • 5
  • 10
  • Thanks! I edited to use `tupled` as it's a bit neater and won't change the syntax if the number of monads changes. It doesn't seem to quite work with *all types* that have a `flatMap` & `map` though. I tried it with a custom Monad and I got a compiler error. Is there any implicit hocus pocus I need to make it work??? (updated question) – samthebest Jan 14 '15 at 14:57
  • 1
    @samthebest |@| is the applicative builder operator. You will need to provide an `Applicative` instance for your custom class, in order to make it work. – Gabriele Petronella Jan 14 '15 at 15:04
0

You can use sequence; I can never remember whether you need shapeless-scalaz for this or not:

(monadA, monadB).sequence
(monadA, monadB, monadC).sequence
lmm
  • 17,386
  • 3
  • 26
  • 37
  • `(Option(12), Option(1)).sequence` returns `Some((Some(12),14))`, which does not seem correct. `bisequence` should work as intended, but it requires explicit types: http://stackoverflow.com/questions/12408086/converting-a-tuple-of-options-to-an-option-of-tuple-with-scalaz-or-shapeless – Gabriele Petronella Jan 14 '15 at 14:22