问题
I have the following property:
import org.scalacheck.Prop.propBoolean
def elementsAreReversed(list: List[Int], reversed: List[Int]): Boolean =
if (list.isEmpty) true else {
val lastIdx = list.size - 1
list.zipWithIndex.forall { case (element, index) =>
element == reversed(lastIdx - index)
}
}
val propReversed = Prop.forAll { list: List[Int] =>
val reversed = list.reverse
if (list.isEmpty)
list == reversed
else {
val hasSameSize = reversed.size == list.size
val hasAllElements = list.forall(reversed.contains)
// It works until I add a label here:
hasSameSize && hasAllElements && elementsAreReversed(list, reversed)
}
If a add a label it breaks:
hasSameSize :| " a label which doesn't let the code compile" &&
hasAllElements &&
elementsAreReversed(list, reversed)
Compiler gives me the following:
Error:(47, 36) No implicit view available from Any => org.scalacheck.Prop. val propReversed = Prop.forAll { list: List[Int] =>
Error:(47, 36) not enough arguments for method forAll:
(implicit p: Any => org.scalacheck.Prop, implicit a1: org.scalacheck.Arbitrary[List[Int]], implicit s1: org.scalacheck.Shrink[List[Int]], implicit pp1: List[Int] => org.scalacheck.util.Pretty) org.scalacheck.Prop. Unspecified value parameters p, a1, s1...
val propReversed = Prop.forAll { list: List[Int] =>
I'm using ScalaCheck version 1.13.4
回答1:
The problem is that you've got an if
expression with the true side having type Boolean
and the false side having type Prop
. The compiler will apply the propBoolean
implicit conversion to a boolean value in cases where it expects a Prop
, but a conditional like this isn't one of those places—instead the compiler simply takes the least upper bound of Boolean
and Prop
and makes that the return type. (Maybe a little more surprisingly, this is true even if the Prop
comes first and the Boolean
second.)
There are several ways you could make this work, but the simplest is just to apply the conversion explicitly:
val propReversed = Prop.forAll { list: List[Int] =>
val reversed = list.reverse
if (list.isEmpty) Prop.propBoolean(list == reversed) else {
val hasSameSize = reversed.size == list.size
val hasAllElements = list.forall(reversed.contains)
hasSameSize :| " a label which doesn't let the code compile" &&
hasAllElements && elementsAreReversed(list, reversed)
}
}
For me this is just another example of the frustrations of fancy implicit conversion-supported DSLs. I like ScalaCheck and use it every day, but I don't really see the value in doing backflips to support slightly more concise usage when the tricks are just going to break down once they start interacting with other corners of Scala's (enormously complicated) syntax.
来源:https://stackoverflow.com/questions/42456685/scalacheck-can-not-cast-boolean-to-prop-instance