Что означает скалярное сообщение "расходящееся неявное расширение"?

Я создал небольшую примерную программу, чтобы попытаться понять, почему большая программа не компилируется.

val o1: Ordered[Int] = 1
val o2: Ordered[Int] = 2
println(o1 < o2)

Когда я передаю это скале, я получаю:

Ordered.scala:3: error: diverging implicit expansion for type scala.math.Ordering[Ordered[Int]]
starting with method ordered in trait LowPriorityOrderingImplicits
println(o1 < o2)
        ^
one error found

Использование "-explaintypes" больше ничего не предлагает. Тем не менее, "-Xlog-implicits" дает следующее:

math.this.Ordering.comparatorToOrdering is not a valid implicit value for scala.math.Ordering[Ordered[Int]] because:
could not find implicit value for parameter cmp: java.util.Comparator[Ordered[Int]]
scala.this.Predef.conforms is not a valid implicit value for Ordered[Int] => java.lang.Comparable[Ordered[Int]] because:
type mismatch;
 found   : <:<[Ordered[Int],Ordered[Int]]
 required: Ordered[Int] => java.lang.Comparable[Ordered[Int]]
/Users/steshaw/Projects/playground/scala/programming-in-scala/Ordered.scala:3: error: diverging implicit expansion for type scala.math.Ordering[Ordered[Int]]
starting with method ordered in trait LowPriorityOrderingImplicits
println(o1 < o2)
        ^
math.this.Ordering.comparatorToOrdering is not a valid implicit value for scala.math.Ordering[Ordered[Int]] because:
could not find implicit value for parameter cmp: java.util.Comparator[Ordered[Int]]
scala.this.Predef.conforms is not a valid implicit value for Ordered[Int] => java.lang.Comparable[Ordered[Int]] because:
type mismatch;
 found   : <:<[Ordered[Int],Ordered[Int]]
 required: Ordered[Int] => java.lang.Comparable[Ordered[Int]]
one error found

но это не помогает мне Хотите знать, что означает это сообщение и как его решить?

[Обновление] Тот же самый код сегодня с Scala 2.11.0 выдает второе сообщение об ошибке в дополнение к первому о "расходящемся неявном расширении". Это второе сообщение весьма полезно.

$ scala Ordered.scala
Ordered.scala:3: error: diverging implicit expansion for type scala.math.Ordering[Ordered[Int]]
starting with method comparatorToOrdering in trait LowPriorityOrderingImplicits
println(o1 < o2)
        ^
/Users/steshaw/Projects/playground/scala/scalac-errors/Ordered.scala:3: error: type mismatch;
 found   : Ordered[Int]
 required: Int
println(o1 < o2)
             ^
two errors found

1 ответ

Решение

Коротко: ваше сообщение об ошибке должно быть просто

error: type mismatch 
found: Ordering[Int]
required: Int.

Причина в том, что в Ordered[A], сравнение сделано с A, не с другими заказами

def <(that: A): Boolean

Которые должны быть o1 < 2не o1 < o2, (конечно 1 < 2 тоже работает, но я ожидаю, что ваш код - просто упрощенная версия чего-то другого)

Однако перед тем, как компилятор сообщит об этой простой ошибке, он должен искать, может ли какая-то неявная в области действия решить проблему. Это может преобразовать Ordering[Int]o2 в Int (не может), или Ordering[Int]o1 к чему-то, что имеет def <(Ordered[Int]) метод, например Ordered[Ordered[Int]], И бывает, что он должен остановить поиск, потому что, кажется, он может продолжаться бесконечно в виде цикла. Правило дано в спецификации, с. От 107 до 109 (спецификация для версии 2.9). Однако правило остановки поиска является пессимистичным, и, возможно, оно отбрасывает строку поиска, которая могла быть успешной, поэтому компилятор считает, что должен сообщить об этом. Хотя на самом деле большую часть времени, как здесь, цикл был должным образом отброшен, и никакого решения не было. Это то, что делает неожиданное сообщение об ошибке. Я думаю, что более простая ошибка должна быть сообщена и более заметна.

Позвольте мне дать некоторые ограниченные объяснения того, почему может быть цикл в неявном поиске. Может быть

implicit def f(implicit a: A): B

Это означает, что если у вас есть неявное Aу вас есть неявное B тоже. Так что получается график между типами: A обеспечивает B, Это сложнее, чем это, на самом деле это гиперграф: implcit def f(implicit a: A, implicit b: B): C: A а также B обеспечивает C,

С дженериками у вас есть бесконечное число типов и бесконечный (гипер) граф, еще более усложненный подтипом (если вам нужен Aлюбой подтип A Сделаю. Добавьте правило подтипов, подразумеваемое ковариацией / контравариантностью)

График может содержать цикл: чтобы получить AВы можете просто предоставить B; чтобы получить BВы можете просто предоставить C; чтобы получить CВы можете просто предоставить A, Это в сумме, если вы предоставите AВы получаете A, который бесполезен, и эту строку поиска нужно отбросить. В данном случае это не проблема: это реальный цикл, и нет риска обойти возможное решение, отбросив его.

Но это может быть более сложным. Поскольку граф бесконечен, поиск может быть бесконечным без точного зацикливания. Если у вас есть

implicit def[A](x: X[X[A]]): X[A] 

тогда, если вы ищете X[Int]Вы можете искать X[X[Int]] вместо этого, но затем, с тем же правилом, вы ищете X[X[X[Int]]] и так далее. Это не точно цикл, но компилятор не выполняет эти строки и называет их расходящимися. За исключением того, что может быть неявное X[X[X...X[Int]]]]] в неявной области где-то, что сделало бы это успехом. Вот почему компилятор сообщает, что эта линия исследования была отброшена.

Другие вопросы по тегам