[英]Scalacheck issue with higher kinds : diverging implicit expansion for type Arbitrary
[英]Extending generic type with Ordered trait makes sbt compiler issue 'diverging implicit expansion for type' error
我有一個實現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
我已經閱讀了類似的問題並閱讀了以下內容:
我知道編譯器對於如何選擇適當的函數進行比較感到困惑。 我知道我可以使用sortBy(obj => obj.fitness)
規避此問題,但是有什么方法可以使用較少的冗長sorted
方法?
Scala使用Ordering[T]
特征對類型T
的集合進行sorted
, min
和max
的方法。 它可以產生的實例Ordering[T]
用於自動T
延伸的Ordered[T]
由於Java的兼容性Ordering[T]
延伸java.util.Comparator[T]
這是在不變的T
,所以Ordering[T]
必須處於不變T
為好。 看到這個問題: SI-7179 。
這意味着Scala無法為實現了Ordered
的類的子類的T
生成Ordering[T]
實例。
在您的代碼中,您具有val collection = List(biggerValue, lesserValue)
,其類型為List[Value[Int]]
。 Value
沒有自己的Ordered
或Ordering
,因此Scala無法對該collection
排序。
要解決此問題,您可以將collection
指定為List[ValueTrait[Int]]
:
val collection = List[ValueTrait[Int]](biggerValue, lesserValue)
或為Value[T]
定義明確的Ordering
:
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)))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.