我已经定义了Seq[Seq[T]]
的排序,使得它是正常的词典排序,除了所有项目(子序列)首先被反转(以便C,B,A
在A,B,C
之前出现A,B,A
1}}但在implicit def ReverseListOrdering[T: Ordering] = new Ordering[Seq[T]] {
override def compare(xs1: Seq[T], xs2: Seq[T]) =
doCompare(xs1.reverse, xs2.reverse)
private def doCompare(xs1: Seq[T], xs2: Seq[T]): Int = (xs1, xs2) match {
case (Nil, Nil) => 0
case (x :: _, Nil) => 1
case (Nil, x :: _) => -1
case (x :: xs, y :: ys) =>
val a = implicitly[Ordering[T]].compare(x, y)
if (a != 0) a else doCompare(xs, ys)
}
}
之后):
List[List[T]]
以前曾在Seq[Seq[T]]
上定义,但我后来意识到我想要所有Nil
;这就是为什么我最初离开模式匹配块中的Nil
,而未能意识到Array
从未匹配,例如空// the Seq[String] declarations are needed; otherwise sample` will be Array[Object] for some reason
val sample = List(
List("Estonia"): Seq[String],
Array("Tallinn", "Estonia"): Seq[String],
List("Tallinn", "Harju", "Estonia"): Seq[String])
println(sample.sorted)
。
后来我尝试运行这段代码:
scala.MatchError: (WrappedArray(Estonia, Tallinn),List(Estonia)) (of class scala.Tuple2)
这样编译得很好,但在运行时会导致以下错误:
Ordering
- 虽然我完全理解错误的原因,但我无法理解(或至少接受)的是,如果Seq[Seq[T]]
在所有doCompare
上成功定义,但表面上有效但显然不兼容(就Seq[Seq[T]]
的定义而言)Array[List[String] | Array[String]]
(即Seq[Seq[T]]
)尝试使用该排序不会产生静态类型错误甚至警告。
这是否是因为模式匹配代码未经过静态验证以涵盖所有可能的"实例" List
并且只处理P.S.
案件?如果是,那么在这种情况下实现类型安全的当前可用解决方法是什么? Scalaz还有什么需要重新审视才能得到合适的解决方案吗?
Seq[Seq[T]]
我知道通过不使用模式匹配并诉诸head
和tail
,我可以轻松取消适用于所有case
的解决方案使用if-else块(或{{1}}语句,如果警卫,这只是表面上更好),但我热衷于学习如何充分利用Scala的类型功能(AFAIK F#和Haskell早餐捕获这些错误);更不用说模式匹配更加优雅和可读。
答案 0 :(得分:2)
这可能更接近:
scala> def cmp[A, B[_] <: Seq[_]](xs: B[A], ys: B[A]) = (xs, ys) match { case (Nil, Nil) => true }
<console>:7: error: pattern type is incompatible with expected type;
found : scala.collection.immutable.Nil.type
required: B[?A1] where type ?A1 (this is a GADT skolem)
def cmp[A, B[_] <: Seq[_]](xs: B[A], ys: B[A]) = (xs, ys) match { case (Nil, Nil) => true }
^
当类型参数在类而不是方法上时,存在已知的综合症。
最近已经出现在ML上。 Here.
比较:
scala> (null: Seq[_]) match { case _: Nil.type => true }
scala.MatchError: null
... 33 elided
scala> (null: List[_]) match { case _: Nil.type => true }
<console>:8: warning: match may not be exhaustive.
It would fail on the following input: List(_)
(null: List[_]) match { case _: Nil.type => true }
^
scala.MatchError: null
... 33 elided
scala> (null: List[_]) match { case Nil => true }
<console>:8: warning: match may not be exhaustive.
It would fail on the following input: List(_)
(null: List[_]) match { case Nil => true }
^
scala.MatchError: null
... 33 elided
抱歉懒惰,但是下床睡觉。
答案 1 :(得分:1)
Scala编译器仅为sealed
类型生成非详尽匹配警告,Seq
不是Seq
。 AFAIK,没有办法强迫它检查,就像尾递归一样。
(AFAIK F#和Haskell在早餐时发现这些错误)
Haskell没有等同于List
;您曾经使用IEnumerable<T>
的代码是等同于Haskell(模数懒惰)的代码,而Scala 在这种情况下会捕获错误。我不太了解F#,但是看http://msdn.microsoft.com/en-us/library/dd547125.aspx,似乎不支持匹配普通{{1}}的模式。
答案 2 :(得分:0)
使用代码:
implicit def ReverseListOrdering[T: Ordering] = new Ordering[Seq[T]] {
override def compare(xs1: Seq[T], xs2: Seq[T]) =
doCompare(xs1.reverse, xs2.reverse)
private def doCompare(xs1: Seq[T], xs2: Seq[T]): Int = (xs1, xs2) match {
case (Seq(), Seq()) => 0
case (x +: _, Seq()) => 1
case (Seq(), x +: _) => -1
case (x +: xs, y +: ys) =>
val a = implicitly[Ordering[T]].compare(x, y)
if (a != 0) a else doCompare(xs, ys)
}
}
正如我所提到的,评论Nil与Seq()的类型不同。例如,WrappedArray不是List。当您使用x :: xs
时 - 它与List匹配。 Array("Tallinn", "Estonia")
转换为WrappedArray。使用Seq
+: