我试图定义一个函数,用于检查泛型Seq是否已排序。
我想出了这个:
import Ordering.Implicits._
def isOrdered[A: Ordering](seq: Seq[A]): Boolean =
seq.sliding(2).map({ case List(a, b) => b > a }).forall(identity)
此时,编译器会抛出“没有为A定义的隐式排序”。
我可以通过将a和b归为以下来解决这个问题:
def isOrdered[A: Ordering](seq: Seq[A]): Boolean =
seq.sliding(2).map({ case List(a: A, b: A) => a < b }).forall(identity)
此时编译器很乐意接受该函数。
我感到好奇的是,以下实现开箱即用:
def isOrdered[A: Ordering](seq: Seq[A]): Boolean =
seq.sliding(2).exists{s => s(0) > s(1)}
据我所知,唯一显着的区别是我不使用部分功能。
任何人都可以解释这种行为吗?
答案 0 :(得分:1)
接受的答案对我来说非常不满意,因为我仍然不知道发生了什么。
我的第一反应是,它必须是暗示+推断的错误,无论是否是他们所知道的。
问题不在于map
的类型参数,因为它减少到匹配:
scala> def f[X: Ordering](seq: Seq[X]) = seq match { case List(a,b) => b > a }
怎么能不起作用?我的猜测是它将与Ordered的不变性有关,因此将List.unapply解包的方式与输入Seq进行比较意味着我们不能依赖于范围中的隐式Ordering。
让我们打开一些调试。 (-Xprint:typer,patmat,-Xlog-implicits,-Yinfer-debug)
这就是case Seq
在typer上翻译的方式:
def f[A](seq: Seq[A])(implicit evidence$1: Ordering[A]): Boolean = seq match {
case collection.this.Seq.unapplySeq[A](<unapply-selector>) <unapply> ((a @ _), (b @ _)) => scala.`package`.Ordering.Implicits.infixOrderingOps[A](b)(evidence$1).>(a)
并在patmat:
def f[A](seq: Seq[A])(implicit evidence$1: Ordering[A]): Boolean = {
case <synthetic> val x1: Seq[A] = seq;
case5(){
<synthetic> val o7: Option[Seq[A]] = collection.this.Seq.unapplySeq[A](x1);
if (o7.isEmpty.unary_!)
if (o7.get.!=(null).&&(o7.get.lengthCompare(2).==(0)))
{
val a: A = o7.get.apply(0);
val b: A = o7.get.apply(1);
matchEnd4(scala.`package`.Ordering.Implicits.infixOrderingOps[A](b)(evidence$1).>(a))
}
else
case6()
else
case6()
};
换句话说,unapply
只返回你的Seq,它得到前两个元素。
case List
应该看起来完全一样,除非它没有输入检查。
scala> import Ordering.Implicits.infixOrderingOps
import Ordering.Implicits.infixOrderingOps
scala> import reflect.ClassTag
import reflect.ClassTag
scala> def f[X](seq: Seq[X])(implicit e1: Ordering[X], e2: ClassTag[X]) = seq match { case xs: List[X] if xs.length == 2 => xs(1) > xs(0) }
f: [X](seq: Seq[X])(implicit e1: Ordering[X], implicit e2: scala.reflect.ClassTag[X])Boolean
答案 1 :(得分:0)
在第一种情况下,
{ case List(a, b) => b > a }
这不起作用,因为您刚刚定义了部分函数,但没有定义这些元素的排序。从某种意义上说,case List(a,b)
代表一个包含a
和b
的列表。现在a
可能意味着什么。 执行a:A, b:A
是有效的,因为现在您定义它是一个包含2个A
类型元素的List。 击>
因为我们已为A
定义了订购。因此第二个工作。
根据第三个:seq.sliding(2).
返回Iterator[List[A]]
。对于迭代器中的每个List[A]
,您调用s(0) > s(1)
。此处s(0)
和s(1)
的类型为A
。因为已定义了绑定A: Ordering
,所以为类型A
定义了排序。在这种情况下s(0) s(1)
。因此它有效。