Scala:在数据结构类型中使函数具有多态性

时间:2017-01-02 01:59:34

标签: scala polymorphism

所以我过去一个月一直在学习Scala,昨天我用简单的排序算法在REPL中玩。使用标准的函数快速排序,很容易在元素类型中创建一个多态的排序函数,但它让我思考:如果我可以使它在数据结构类型中也具有多态性呢?为ListVector等提供单独的功能令人讨厌。当然,我可以只用一个Seq[E],但似乎无法保证Seq[E]的底层实现。所有线性集合都实现Seq,它具有我们需要的所有功能(filterapplyappend),因此我们应该能够拥有一个可以排序的函数所有线性集合,对吗?我想出了以下代码:

object QSort {
  def qsort[E, D[E] <: Seq[E]](s: D[E])(c: (E, E) => Int): D[E] = {
    if (s.length <= 1) s
    else {
      val pivot: E = s(s.length / 2)
      qsort[E, D](s.filter((x: E) => c(x, pivot) < 0))(c)
              .append(s.filter((x: E) => c(x, pivot) == 0))
              .append(qsort[E, D](s.filter((x: E) => c(x, pivot) > 0))(c))
    }
  }
} 

它采用一些D[E]的子类作为Seq[E]的子类和比较器函数,并且应该应用效率极低的快速排序。但是,编译器说当我调用filter时,类型不匹配,因为过滤器返回Seq[E]而不是D[E]。为什么filter不返回D[E],这种多态性是否真的可能?

1 个答案:

答案 0 :(得分:1)

我非常推荐阅读更多有关CanBuildFrom的内容,但以下是如何将其用于您的问题:

scala> :pa
// Entering paste mode (ctrl-D to finish)

import scala.collection.generic.CanBuildFrom

object QSort {
    def qsort[E, D[E] <: Seq[E]]
        (s: D[E])(c: (E, E) => Int)
        (implicit cbf: CanBuildFrom[D[E], E, D[E]]): D[E] =
    {
        if (s.size <= 1)
            s
        else
        {
            val pivot: E = s(s.size / 2)

            (qsort(s.filter((x: E) => c(x, pivot) < 0))(c) ++
            s.filter((x: E) => c(x, pivot) == 0) ++
            qsort(s.filter((x: E) => c(x, pivot) > 0))(c)).to[D]
        }
    }
}

// Exiting paste mode, now interpreting.

import scala.collection.generic.CanBuildFrom
defined module QSort

scala> val l = List(1, -10, 12, 2)
l: List[Int] = List(1, -10, 12, 2)

scala> val c = (a: Int, b:Int) => if (a == b) 0 else if (a < b) 1 else -1
c: (Int, Int) => Int = <function2>

scala> QSort.qsort(l)(c)
res0: List[Int] = List(12, 2, 1, -10)

scala> QSort.qsort(l.toSeq)(c)
res1: scala.collection.immutable.Seq[Int] = List(12, 2, 1, -10)

scala> QSort.qsort(l.toVector)(c)
res2: Vector[Int] = Vector(12, 2, 1, -10)

正如您所看到的,我传递给qsort的任何类型都与我回来的类型相同。