繁体   English   中英

Scala上下文意外绑定

[英]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 Seqcase 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)代表一个包含ab的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM