scala - 在Scalaz中对一系列析取进行分区

标签 scala functional-programming scalaz

使用 Scalaz 将 Seq[A\/B] 划分为 (Seq[A], Seq[B]) 的最佳方法是什么?

最佳答案

有一个方法:分开 defined在 MonadPlus。这个类型类是 Monad 和 PlusEmpty(广义 Monoid)的组合。所以你需要为 Seq 定义实例:

1) MonadPlus[Seq]

implicit val seqmp = new MonadPlus[Seq] {
  def plus[A](a: Seq[A], b: => Seq[A]): Seq[A] = a ++ b
  def empty[A]: Seq[A] = Seq.empty[A]
  def point[A](a: => A): Seq[A] = Seq(a)
  def bind[A, B](fa: Seq[A])(f: (A) => Seq[B]): Seq[B] = fa.flatMap(f)
}

Seq 已经是一元的了,所以 pointbind 很简单,emptyplus 是 monoid 操作Seqfree monoid

2) 可折叠[\/]

implicit val bife = new Bifoldable[\/] {
    def bifoldMap[A, B, M](fa: \/[A, B])(f: (A) => M)(g: (B) => M)(implicit F: Monoid[M]): M = fa match {
      case \/-(r) => g(r)
      case -\/(l) => f(l)
    }

    def bifoldRight[A, B, C](fa: \/[A, B], z: => C)(f: (A, => C) => C)(g: (B, => C) => C): C = fa match {
      case \/-(r) => g(r, z)
      case -\/(l) => f(l, z)
    }
  }

也很简单,标准折叠,但对于具有两个参数的类型构造函数。

现在你可以单独使用了:

val seq: Seq[String \/ Int] = List(\/-(10), -\/("wrong"), \/-(22), \/-(1), -\/("exception"))
scala> seq.separate
res2: (Seq[String], Seq[Int]) = (List(wrong, number exception),List(10, 22, 1))

更新

感谢 Kenji Yoshida ,有is一个 Bitraverse[\/],所以你只需要 MonadPlus。

还有一个使用 foldLeft 的简单解决方案:

seq.foldLeft((Seq.empty[String], Seq.empty[Int])){ case ((as, ai), either) =>
  either match {
    case \/-(r) => (as, ai :+ r)
    case -\/(l) => (as :+ l, ai)
  }
}

关于scala - 在Scalaz中对一系列析取进行分区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19485683/

相关文章:

performance - 如何找出我的 Scala 代码中使用了哪些隐式

java - 如何在 Scala 中获取 Java 的 int.class?

scala - Spark 从 InputStream 创建数据帧?

scala - 无形 .toHList 的行为

javascript - 如果我的值需要根据以前的值进行更新,我该如何编写纯函数代码?

scala - 组合返回选项的函数

java - 使用 Akka 微内核有哪些常见用例?

python - 将功能分解为被动(算法)和主动(执行)对象

Haskell的函数应用运算符($)用法

scala - 如何使用隐式转换将List [A]转换为List [B]