ScalaCheck can not cast boolean to Prop instance

▼魔方 西西 提交于 2019-12-23 12:37:07

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!