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

Scala:使函数在数据结构类型中多态,scala,polymorphism,Scala,Polymorphism,所以我在过去的一个月里一直在学习Scala,昨天我在REPL中玩简单的排序算法。使用标准函数快速排序,很容易使排序函数在元素类型中具有多态性,但这让我想到:如果我也能使它在数据结构类型中具有多态性呢?为列表、向量等单独设置函数很烦人。当然,我可以让它只取一个Seq[E],但似乎无法保证该Seq[E]的底层实现。所有的线性集合都实现了Seq,它具有我们需要的所有功能(过滤器,应用,和附加),所以我们应该能够有一个功能来对所有线性集合进行排序,对吗?我想出了以下代码: object QSort {

所以我在过去的一个月里一直在学习Scala,昨天我在REPL中玩简单的排序算法。使用标准函数快速排序,很容易使排序函数在元素类型中具有多态性,但这让我想到:如果我也能使它在数据结构类型中具有多态性呢?为
列表
向量
等单独设置函数很烦人。当然,我可以让它只取一个
Seq[E]
,但似乎无法保证该
Seq[E]
的底层实现。所有的线性集合都实现了
Seq
,它具有我们需要的所有功能(
过滤器
应用
,和
附加
),所以我们应该能够有一个功能来对所有线性集合进行排序,对吗?我想出了以下代码:

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))
    }
  }
} 
objectqsort{
def qsort[E,D[E]Int:D[E]={
如果(s.长度c(x,枢轴)<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
时,存在类型不匹配,因为filter返回的是
Seq[E]
,而不是
D[E]
。为什么
过滤器
不返回
D[E]
,而且这种多态性实际上是可能的吗?

我强烈建议阅读更多有关
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)
scala>:pa
//进入粘贴模式(按ctrl-D键完成)
导入scala.collection.generic.CanBuildFrom
对象QSort{
def qsort[E,D[E]Int)
(隐式cbf:CanBuildFrom[D[E],E,D[E]]):D[E]=
{
如果(s.尺寸c(x,枢轴)<0))(c)++
s、 过滤器((x:E)=>c(x,轴)==0)++
qsort(s.filter((x:E)=>c(x,pivot)>0))(c))到[D]
}
}
}
//正在退出粘贴模式,现在正在解释。
导入scala.collection.generic.CanBuildFrom
定义模块QSort
scala>vall=List(1,-10,12,2)
l:List[Int]=List(1,-10,12,2)
scala>valc=(a:Int,b:Int)=>if(a==b)0 else if(aInt=
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
的是什么类型,都是我得到的相同类型。

“你可以声明它只接受Seq[E],但这样就不能保证……某样东西”?因此,你向该D[E]声明它相反,在你看来,它到底提供了什么样的保证?这种多态性确实是可能的。一种方法是使用Builder特性(和CanBuildFrom)正如在其他集合中所做的那样。总体思路是排序,创建一个新的Seq,然后从CanBuildFrom实例创建一个生成器,然后将结果Seq附加到生成器并返回结果。例如,请看一看。