[英]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.