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