你如何使一个类flatMappable?

时间:2014-10-06 16:02:04

标签: scala scala-collections

我发现自己想写这个:

def allAsAndFs(node: Node): PairOfSeqs[Action, Factor] =
  node.regularNames.flatMap { name => regularAsAndFs(name) } ++
  node.specialNames.flatMap { name => specialAsAndFs(name) }

其中:

def regularNames: Seq[String]
def specialNames: Seq[String]

def regularAsAndFs(name: String): PairOfSeqs[Action, Factor]
def specialAsAndFs(name: String): PairOfSeqs[Action, Factor]

class PairOfSeqs[A, B](as: Seq[A], bs: Seq[B]) {
  def ++(that: PairOfSeqs[A, B]): PairOfSeqs[A, B] =
    PairOfSeqs(as ++ that.as, bs ++ that.bs)
  . . .
}

我需要做些什么才能使flatMap合并PairsOfSeqs 调用适当的++方法?

看起来PairOfSeqs应该扩展GenTraversableOnce,但是 GenTraversableOnce有一个相当惊人的47个抽象方法来覆盖。

这是一种惯用的Scalastic方法吗?

1 个答案:

答案 0 :(得分:3)

您使用的是flatMap的一些非标准概念。正常类型签名是

class C[A] {
  def flatMap[B](f: A => C[B]): C[B] = ???
}

但是你想要(类似于 - 这不会编译):

  def foo[D <: { def ++(d: D): D }](f: A => D): D

更像fold而不是flatMap

一种可能性是使PairOfSeqs成为一个完整的集合。这将是艰难的,因为类型真的不排队那么好,因为扩展集合很困难。 (奖励/努力比率可能很好,因为即使努力很大,奖励也是巨大,如果你真的需要它。)

也许最好的可能性就是在Seq上有一个扩展方法。

case class PairOfSeqs[A, B](as: Seq[A], bs: Seq[B]) {
  def ++(that: PairOfSeqs[A, B]): PairOfSeqs[A,B] =
    PairOfSeqs(as ++ that.as, bs ++ that.bs)
}

implicit class SeqCanPairMap[A](val underlying: Seq[A]) extends AnyVal {
  def flatPair[B,C](f: A => PairOfSeqs[B,C]): PairOfSeqs[B,C] = {
    val ps = underlying.map(f)
    PairOfSeqs(ps.map(_.as).fold(Seq[B]())(_ ++ _), ps.map(_.bs).fold(Seq[C]())(_ ++ _))
  }
}

Seq("fish", "fowl").flatPair(s => new PairOfSeqs(s.map(_.toChar), s.map(_.toInt)))

还有其他各种选项(例如,在flatMap上定义更传统的PairOfSeqs,以及从常规seqs到具有空第二个插槽的PairOfSeqs的转换,但这可能涵盖您的使用情况不错。

最后,要制作课程flatMappable,您只需要定义flatMap即可。特别是,理解可以使用它。 (但是你也需要一个map,否则它对于理解不会有用。)