[英]Scala context bound unexpectedly not working
我试图定义一个函数来检查通用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)}
据我所知,唯一的区别是我不使用局部函数。
谁能解释这种行为?
从某种意义上说,我仍然不满意所接受的答案,这使我非常不满意。
我的第一个反应是,无论这是否是他们所知道的,它都必须是带有隐式+推断的错误。
问题不存在于map
的类型参数中,因为它简化为匹配项:
scala> def f[X: Ordering](seq: Seq[X]) = seq match { case List(a,b) => b > a }
那怎么不行? 我的推测是,这将与Ordered的不变性有关,以便将List.unapply的解压缩方式与输入Seq进行比较,这意味着我们不能依赖范围中的隐式Ordering。
让我们打开一些调试。 (-Xprint:打字机,patmat,-Xlog隐式,-Yinfer调试)
这是在打字机上翻译case Seq
的case Seq
:
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
也许这种赤字正在发挥作用 。
在第一种情况下,
{ case List(a, b) => b > a }
这是行不通的,因为您刚刚定义了部分函数,但没有定义那些元素的顺序。 在某种意义上说case List(a,b)
代表一个包含a
和b
的List。 现在, a
意味着任何东西。
执行
a:A, b:A
之所以有效,是因为现在您定义它是一个包含2个类型为
A
元素的列表。
并且因为我们为A
定义了Ordering。 因此,第二件作品。
按照第三条: seq.sliding(2).
返回Iterator[List[A]]
。 对于迭代器中的每个List[A]
,您正在调用s(0) > s(1)
。 此处s(0)
和s(1)
的类型为A
由于已定义了边界A: Ordering
,因此已为类型A
定义了排序。 在这种情况下s(0) s(1)
。 因此,它起作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.