Что означает скалярное сообщение «расходящееся неявное расширение»? - PullRequest
15 голосов
/ 31 октября 2011

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

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

Когда я передаю это в 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)
        ^
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 Ответ

28 голосов
/ 31 октября 2011

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

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]]]]] в неявном объеме где-то, что сделает его успешным.Вот почему компилятор сообщает, что эта линия исследования была отброшена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...