我正在使用scala实现一些常见的算法。在尝试重新创建冒泡排序时,我遇到了这个问题
这是一个内部循环的实现,它将值冒泡到顶部:
def pass(xs:List[Int]):List[Int] = xs match {
case Nil => Nil
case x::Nil => x::Nil
case l::r::xs if(l>r) => r::pass(l::xs)
case l::r::xs => l::pass(r::xs)
}
我的问题是案例Nil => Nil
。我知道我需要这个是因为我可以将Nil
应用于此功能。有没有办法确保Nil
不能以满足编译器的方式作为参数提供,以便我可以消除这种情况?
答案 0 :(得分:4)
List有两个子类型,Nil和::,so ::表示至少有一个元素的列表。
def pass(xs: ::[Int]):List[Int] = xs match {
case x::Nil => x::Nil
case l::r::xs if(l>r) => r::pass(new ::(l,xs))
case l::r::xs => l::pass(new ::(r, xs))
}
答案 1 :(得分:2)
这大致对应于原始类型的细化,您可以在其中编写一个类型,其成员是初始类型的子集。然后,您会显示,对于您的函数的每个输入x
,x
都是非Nil
。因为这需要大量证据(您可以使用子集类型在Coq中使用依赖类型实现此功能),在这种情况下更好的做法可能是引入一个新类型,这是一个list没有Nil
构造函数,只有cons的构造函数和单个元素。
编辑:由于Scala允许您使用List类型的子类型来强制执行此操作,因此您可以使用该子类型在类型系统中进行可判断性证明。这是仍然一个证据,在某种意义上,任何类型检查都对应于程序确实存在某种类型的证据,它只是编译器可以完全证明的东西。
答案 2 :(得分:2)
在这种情况下,您只需使用case
子句命令:
def pass(xs:List[Int]):List[Int] = xs match {
case l::r::xs if(l>r) => r::pass(l::xs)
case l::r::xs => l::pass(r::xs)
case xs => xs
}
前两个子句仅匹配具有一个或多个元素的列表。最后一个句子将在其他地方匹配。