Связанный контекст Scala неожиданно не работает
Я попытался определить функцию, которая будет проверять, отсортирован ли общий 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)}
Где, насколько я могу судить, единственное существенное отличие состоит в том, что я не использую частичную функцию.
Кто-нибудь может объяснить это поведение?
2 ответа
В первом случае
{ case List(a, b) => b > a }
Это не работает, потому что вы только что определили частичную функцию, но не упорядочили эти элементы. В смысле case List(a,b)
представляет список, содержащий a
а также b
, Сейчас a
может означать что угодно. дела a:A, b:A
работает, потому что теперь вы определяете, что это список, содержащий 2 элемента типа A
,
И потому что мы определили порядок для 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)
, Следовательно, это работает.
Принятый ответ для меня довольно неудовлетворителен, в том смысле, что я до сих пор не знаю, что происходит.
Моя первая реакция: "Это должно быть ошибкой со следствиями + умозаключения, независимо от того, знают они об этом или нет".
Проблема не в, скажем, параметре типа для map
, поскольку сводится к совпадению:
scala> def f[X: Ordering](seq: Seq[X]) = seq match { case List(a,b) => b > a }
Как это может не работать? Я предполагаю, что это будет связано с неизменностью Ordered, поэтому способ распаковки List.unapply по сравнению с входным Seq означает, что мы не можем полагаться на неявное упорядочение в области видимости.
Давайте включим некоторую отладку. (-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)
и при патмате:
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
Может быть, этот дефицит в игре.