Я вижу, что кажется очень очевидной ошибкой в scalacheck, так что если это действительно так, я не вижу, как люди используют его для рекурсивных структур данных.
Эта программа выходит из строя с StackOverflowError
до того, как scalacheck возьмет верх, при построении значения Arbitrary
. Обратите внимание, что тип Tree
и генератор для Tree
принимается стенографически из этого учебника по скаляке.
package treegen
import org.scalacheck._
import Prop._
class TreeProperties extends Properties("Tree") {
trait Tree
case class Node(left: Tree, right: Tree) extends Tree
case class Leaf(x: Int) extends Tree
val ints = Gen.choose(-100, 100)
def leafs: Gen[Leaf] = for {
x <- ints
} yield Leaf(x)
def nodes: Gen[Node] = for {
left <- trees
right <- trees
} yield Node(left, right)
def trees: Gen[Tree] = Gen.oneOf(leafs, nodes)
implicit lazy val arbTree: Arbitrary[Tree] = Arbitrary(trees)
property("vacuous") = forAll { t: Tree => true }
}
object Main extends App {
(new TreeProperties).check
}
Что странно, что изменения, которые не должны влиять на что-либо, похоже, изменят программу так, чтобы она работала. Например, если вы измените определение trees
на это, оно пройдет без каких-либо проблем:
def trees: Gen[Tree] = for {
x <- Gen.oneOf(0, 1)
t <- if (x == 0) {leafs} else {nodes}
} yield t
Даже незнакомец, если вы измените структуру двоичного дерева, чтобы значение сохранялось на Node
, а не на Leaf
s, и измените определение leafs
и nodes
:
def leafs: Gen[Leaf] = Gen.value(Leaf())
def nodes: Gen[Node] = for {
x <- ints // Note: be sure to ask for x first, or it'll StackOverflow later, inside scalacheck code!
left <- trees
right <- trees
} yield Node(left, right, x)
Он также отлично работает.
Что здесь происходит? Почему создается значение Arbitrary
, изначально вызывающее переполнение стека? Почему кажется, что генераторы scalacheck настолько чувствительны к незначительным изменениям, которые не должны влиять на поток управления генераторами?
Почему мое выражение выше с oneOf(0, 1)
не эквивалентно оригиналу oneOf(leafs, nodes)
?