Очевидная интуиция заключается в том, что определение myGenFormula
является рекурсивным. Это было бы объяснением переполнения стека.
Одна часть решения этой проблемы - добавление Gen.lzy
в правильные места для myGenFormula
. Это гарантирует выполнение одного пути генераторов и исключает ненужное выполнение всех рекурсивных генераторов.
Существует вторичная проблема с определением для myGenFormula
, которая вызывает переполнение стека. Как написано, определение для myGenFormula
статистически вряд ли закончится. Генератор genVar
является оконечным генератором, но он одинаково взвешивается с другими несимметричными генераторами. Ничто не мешает ScalaCheck генерировать бесконечную глубину структур данных до достижения переполнения стека.
Есть два способа помочь завершить рекурсивные генераторы в ScalaCheck. Вы можете передать числовой аргумент глубины с помощью Gen.sized
вашим генераторам, или вы можете использовать Gen.frequency
.
Существует также проблема инициализации с взаимно рекурсивными генераторами. Вам нужно использовать ключевое слово lazy
в генераторе val
s, которое ссылается на myGenFormula
, чтобы избежать этого.
Вот решение, которое включает в себя lazy
, Gen.lzy
и Gen.frequency
в вашем коде, так что оно запускается и завершается. Вам, вероятно, нужно будет настроить свои потребности в тестировании.
lazy val genAnd = for {
left <- myGenFormula
right <- myGenFormula
} yield And(left, right)
lazy val genOr = for {
left <- myGenFormula
right <- myGenFormula
} yield Or(left, right)
lazy val genImplies = for {
left <- myGenFormula
right <- myGenFormula
} yield Implies(left, right)
lazy val genNot = for {
son <- myGenFormula
} yield Not(son)
val genVar =
Gen.oneOf(Var("A"), Var("B"))
val myGenFormula: Gen[FormulaWff] =
Gen.frequency(
4 -> genVar,
1 -> Gen.lzy(genAnd),
1 -> Gen.lzy(genImplies),
1 -> Gen.lzy(genOr),
1 -> Gen.lzy(genNot))
property("myGenFormula") = {
Prop.forAll(myGenFormula) { f: FormulaWff =>
true
}
}