Расширение универсального типа с помощью упорядоченной черты приводит к тому, что компилятор sbt выдает ошибку "расходящегося неявного расширения для типа"
У меня есть черта, реализующая упорядоченную черту Scala:
package stackQuestions
trait ValueTrait[TYPE] extends Ordered[ValueTrait[TYPE]]{
def value: Double
}
и подкласс:
package stackQuestions
class Value[A](list: List[A], function: (A, A) => Double) extends ValueTrait[A] {
private val _value: Double = list.zip(list.tail).map(pair => function(pair._1, pair._2)).sum
override def value: Double = _value
override def compare(that: ValueTrait[A]): Int = {
(this.value - that.value).signum
}
}
В основном, когда объект Value создается с предоставленной функцией, значение вычисляется. Чего я хочу добиться, так это отсортировать коллекцию объектов Value по их значению. Это должно быть гарантировано заказанной чертой. Я написал несколько простых тестов для этого:
package stackQuestions
import org.scalatest.FunSpec
class ValueTest extends FunSpec {
def evaluationFunction(arg1: Int, arg2: Int): Double = {
if (arg1 == 1 && arg2 == 2) return 1.0
if (arg1 == 2 && arg2 == 1) return 10.0
0.0
}
val lesserValue = new Value(List(1, 2), evaluationFunction) // value will be: 1.0
val biggerValue = new Value(List(2, 1), evaluationFunction) // value will be: 10.0
describe("When to Value objects are compared") {
it("should compare by calculated value") {
assert(lesserValue < biggerValue)
}
}
describe("When to Value objects are stored in collection") {
it("should be able to get max value, min value, and get sorted") {
val collection = List(biggerValue, lesserValue)
assertResult(expected = lesserValue)(actual = collection.min)
assertResult(expected = biggerValue)(actual = collection.max)
assertResult(expected = List(lesserValue, biggerValue))(actual = collection.sorted)
}
}
}
Однако когда sbt test -Xlog-implicits
Я получаю сообщения об ошибках:
[info] Compiling 1 Scala source to /project/target/scala-2.11/test-classes ...
[error] /project/src/test/scala/stackQuestions/ValueTest.scala:24:64: diverging implicit expansion for type Ordering[stackQuestions.Value[Int]]
[error] starting with method $conforms in object Predef
[error] assertResult(expected = lesserValue)(actual = collection.min)
[error] ^
[error] /project/src/test/scala/stackQuestions/ValueTest.scala:25:64: diverging implicit expansion for type Ordering[stackQuestions.Value[Int]]
[error] starting with method $conforms in object Predef
[error] assertResult(expected = biggerValue)(actual = collection.max)
[error] ^
[error] /project/src/test/scala/stackQuestions/ValueTest.scala:27:83: diverging implicit expansion for type scala.math.Ordering[stackQuestions.Value[Int]]
[error] starting with method $conforms in object Predef
[error] assertResult(expected = List(lesserValue, biggerValue))(actual = collection.sorted)
[error] ^
[error] three errors found
[error] (Test / compileIncremental) Compilation failed
[error] Total time: 1 s, completed 2018-09-01 08:36:18
Я вырыл для подобных проблем и после прочтения:
- Что означает скалярное сообщение "расходящееся неявное расширение"?,
- Почему я получаю ошибку "расходящегося неявного расширения" при попытке отсортировать экземпляры упорядоченного класса?,
- Как я могу решить неявное расширение расходящихся для типа,
- scala - Запутывающая ошибка "расходящегося неявного расширения" при использовании "sortBy",
Я узнаю, что компилятор не понимает, как правильно выбрать функцию для сравнения. Я знаю, что могу обойти это, используя sortBy(obj => obj.fitness)
но есть ли способ использовать менее многословно sorted
метод?
1 ответ
Скала использует Ordering[T]
черта для методов sorted
, min
а также max
из коллекции типа T
, Это может генерировать случаи Ordering[T]
автоматически для T
это простирается Ordered[T]
,
Из-за совместимости с Java Ordering[T]
продолжается java.util.Comparator[T]
, который инвариантен в T
, так Ordering[T]
должен быть инвариантным в T
также. Смотрите этот выпуск: SI-7179.
Это означает, что Scala не может генерировать экземпляры Ordering[T]
за T
это подклассы классов, которые реализуют Ordered
,
В вашем коде у вас есть val collection = List(biggerValue, lesserValue)
, который имеет тип List[Value[Int]]
, Value
не имеет своего Ordered
или же Ordering
так что Скала не может отсортировать это collection
,
Чтобы исправить вы можете указать collection
иметь тип List[ValueTrait[Int]]
:
val collection = List[ValueTrait[Int]](biggerValue, lesserValue)
Или определите явное Ordering
за Value[T]
:
object Value {
implicit def ord[T]: Ordering[Value[T]] =
Ordering.by(t => t: ValueTrait[T])
}
Вы также можете рассмотреть возможность использования другой конструкции в этой задаче, если она соответствует вашим другим требованиям:
В вашем коде все экземпляры ValueTrait[TYPE]
иметь значение типа Double
и различия в подклассе и TYPE
не кажется важным во время выполнения. Таким образом, вы можете просто определить case class Value(value: Double)
и иметь разные фабричные методы для создания Value
это из разных видов аргументов.
case class Value(value: Double) extends Ordered[Value] {
override def compare(that: Value): Int = this.value compareTo that.value
}
object Value {
def fromList[A](list: List[A], function: (A, A) => Double): Value =
Value((list, list.tail).zipped.map(function).sum)
}
И использование:
scala> val lesserValue = Value.fromList(List(1, 2), evaluationFunction)
lesserValue: Value = Value(1.0)
scala> val biggerValue = Value.fromList(List(2, 1), evaluationFunction)
biggerValue: Value = Value(10.0)
scala> val collection = List(biggerValue, lesserValue)
collection: List[Value] = List(Value(10.0), Value(1.0))
scala> (collection.min, collection.max, collection.sorted)
res1: (Value, Value, List[Value]) = (Value(1.0),Value(10.0),List(Value(1.0), Value(10.0)))