【问题标题】:Adding custom collection operations in scala 2.13 to arbitrary collections of specific types将 scala 2.13 中的自定义集合操作添加到特定类型的任意集合
【发布时间】:2019-10-25 19:05:16
【问题描述】:

注意 - 下面描述的操作现在以partitionMap 的形式存在于标准库中,但我相信关于如何实现更一般的目标仍然是一个有效的问题

关于 scala 2.13 的问题 - 在需要限制输入集合的元素类型的情况下添加自定义集合操作时,如何使用/构造特定类型的集合?例如如何定义:

def split[CC[_], A, B](coll: CC[Either[A, B]]): (CC[A], CC[B])

按照documentation,我设法实现了以下目标:

import collection.generic.IsIterable
import scala.collection.{BuildFrom, Factory}

class SplitOperation[Repr, S <: IsIterable[Repr]](coll: Repr, itr: S) {
  def split[A, B, AS, BS](
    implicit bfa: BuildFrom[Repr, A, AS], 
             bfb: BuildFrom[Repr, B, BS], 
             ev: itr.A =:= Either[A, B]): (AS, BS) = {

    val ops = itr(coll)
    val as = bfa.fromSpecific(coll)(ops.iterator.map(ev).collect { case Left(a) => a })
    val bs = bfb.fromSpecific(coll)(ops.iterator.map(ev).collect { case Right(b) => b })

    (as, bs)
  }
}

implicit def SplitOperation[Repr](coll: Repr)(implicit itr: IsIterable[Repr]): SplitOperation[Repr, itr.type] =
new SplitOperation(coll, itr)

但是,我需要在使用站点提供类型,否则我会得到发散的隐式扩展。

scala> List(Left("bah"), Right(1), Left("gah"), Right(2), Right(3))
res1: List[scala.util.Either[String,Int]] = List(Left(bah), Right(1), Left(gah), Right(2), Right(3))

scala> res1.split
            ^
       error: diverging implicit expansion for type scala.collection.BuildFrom[List[scala.util.Either[String,Int]],A,AS]

但以下工作:

scala> res1.split[String, Int, List[String], List[Int]]
res4: (List[String], List[Int]) = (List(bah, gah),List(1, 2, 3))

编辑

class SplitOperation[X, CC[_], S <: IsIterable[CC[X]]](coll: CC[X], itr: S) {
  def split[A, B](implicit bfa: BuildFrom[CC[X], A, CC[A]], bfb: BuildFrom[CC[X], B, CC[B]], ev: itr.A =:= Either[A, B]): (CC[A], CC[B]) = {
    val ops = itr(coll)
    val as = bfa.fromSpecific(coll)(ops.iterator.map(ev).collect { case Left(a) => a })
    val bs = bfb.fromSpecific(coll)(ops.iterator.map(ev).collect { case Right(b) => b })

    (as, bs)
  }
}

implicit def SplitOperation[A, B, CC[_]](coll: CC[Either[A, B]])(implicit itr: IsIterable[CC[Either[A, B]]]): SplitOperation[Either[A, B], CC, itr.type] =
  new SplitOperation(coll, itr)

给了我一点改善。现在只需要在调用点提供类型参数AB即可:

scala> l.split[String, Int]
res2: (List[String], List[Int]) = (List(bah, gah),List(1, 2))

【问题讨论】:

    标签: scala scala-2.13


    【解决方案1】:

    这似乎有效:

    class SplitOperation[A, B, CC[_], S <: IsIterable[CC[Either[A, B]]]](coll: CC[Either[A, B]], itr: S) {
      def split(implicit bfa: BuildFrom[CC[Either[A, B]], A, CC[A]], bfb: BuildFrom[CC[Either[A, B]], B, CC[B]], ev: itr.A =:= Either[A, B]): (CC[A], CC[B]) = {
        val ops = itr(coll)
        val as = bfa.fromSpecific(coll)(ops.iterator.map(ev).collect { case Left(a) => a })
        val bs = bfb.fromSpecific(coll)(ops.iterator.map(ev).collect { case Right(b) => b })
    
        (as, bs)
      }
    }
    
    implicit def SplitOperation[A, B, CC[_]](coll: CC[Either[A, B]])(implicit itr: IsIterable[CC[Either[A, B]]]): SplitOperation[A, B, CC, itr.type] =
      new SplitOperation(coll, itr)
    

    【讨论】:

    • 肯定对cbf 模式进行了大规模改进:)
    【解决方案2】:

    在您的情况下,您不想抽象集合类型构造函数的“种类”(CC[_]CC[_, _] 等),您始终使用 CC[_] 种类,所以您不需要使用IsIterable

    我认为也没有必要支持“排序”集合(例如SortedSet),因为Either 没有Ordering 实例,因此您不需要使用BuildFrom

    implicit class SplitOperation[A, B, CC[X] <: IterableOps[X, CC, CC[X]]](coll: CC[Either[A, B]]) {
      def split: (CC[A], CC[B]) = {
        val as = coll.iterableFactory.from(coll.iterator.collect { case Left(a) => a })
        val bs = coll.iterableFactory.from(coll.iterator.collect { case Right(b) => b })
        (as, bs)
      }
    }
    

    https://scastie.scala-lang.org/64QxHwteQN2i3udSxCa3yw

    【讨论】:

    • 像往常一样,Array 是问题孩子。这两种解决方案都不适用于Array[Either[A,B]],因为Array 不继承自IterableOps。但是Array 确实iterableFactory 方法。有没有办法让 Array 也能做到这一点?
    • 好点。要支持Array,则需要IsIterable(和BuildFrom),如@oxbow_lakes 的解决方案
    猜你喜欢
    • 2011-10-23
    • 2014-11-15
    • 1970-01-01
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    • 2019-08-08
    • 2011-06-12
    • 1970-01-01
    相关资源
    最近更新 更多