将 monad 组合成元组运算符 scalaz

Combine monads into tuples operator scalaz

所以 Scala 中一个非常非常常见的模式是 for comprehension 如下:

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

对于 3 元组,...,n 元组类似。这在我的代码中变得如此普遍,我想 scalaz 提供了一些很棒的运算符来为我做这件事,例如monadA funnyOperator monadB funnyOperator monadC。我环顾四周,似乎找不到任何东西。因此,我为 2 元组和 3 元组定义了自己的隐式 class,但更愿意使用 scalaz。

奖金

响应当前接受的答案,希望看到有人告诉如何进行编译:

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

不给:

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

奖金解决方案:

您需要"provide an applicative instance"例如

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)
}

可以使用sequence;我永远不记得你是否需要 shapeless-scalaz:

(monadA, monadB).sequence
(monadA, monadB, monadC).sequence

鉴于每个 Monad 都是一个 Applicative 你也可以使用

(monadA |@| monadB).tupled

例如

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