簡體   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