ScalaCheck 的 Gen
API docs 解释 lazy val sized
:
看下面的例子:
import org.scalacheck.Gen.{sized, posNum}
scala> sized( s => { println(s); posNum[Int] })
res12: org.scalacheck.Gen[Int] = org.scalacheck.Gen$$anon$3@6a071cc0
scala> res12.sample
100
res13: Option[Int] = Some(12)
scala> res12.sample
100
res14: Option[Int] = Some(40)
上面输出中的
generation size
,即 100 是什么意思? 最佳答案
sized
提供对 Scalacheck 的“size”参数的访问。此参数指示生成器生成的值应该有多大。此参数在以下几种情况下很有用:
Gen.sized
的伴侣是 Gen.resize
,它允许您更改生成器的大小,如 Gen.resize(10, Gen.alphaNumString)
将生成不超过 10 个字符的字母数字字符串。大多数内置生成器以某种方式使用
sized
,例如 Gen.buildableOf
(它是所有列表和容器生成器的基础):一个简单的例子
要了解如何使用
Gen.size
,请查看“大小生成器”中的示例( Generators ,Scalacheck 用户指南):def matrix[T](g: Gen[T]): Gen[Seq[Seq[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
Gen.listOfN(side, Gen.listOfN(side, g))
}
这个生成器使用“size”来限制矩阵的维度,这样整个矩阵的条目永远不会超过“size”参数。换句话说,如果您的问题的大小为 100,则生成的矩阵将有 10 行和 10 列,总共有 100 个条目。
递归数据结构
“大小”对于确保递归数据结构的生成器终止特别有用。考虑以下示例,该示例生成二叉树的实例并使用
size
来限制每个分支的高度以确保生成器在某个点终止:import org.scalacheck.Gen
import org.scalacheck.Arbitrary.arbitrary
sealed abstract class Tree
case class Node(left: Tree, right: Tree, v: Int) extends Tree
case object Leaf extends Tree
val genLeaf = Gen.const(Leaf)
val genNode = for {
v <- arbitrary[Int]
left <- Gen.sized(h => Gen.resize(h/2, genTree))
right <- Gen.sized(h => Gen.resize(h/2, genTree))
} yield Node(left, right, v)
def genTree: Gen[Tree] = Gen.sized { height =>
if (height <= 0) {
genLeaf
} else {
Gen.oneOf(genLeaf, genNode)
}
}
请注意节点的生成器如何递归生成树,但只允许它们“大小”的一半。树生成器反过来只会在其大小耗尽时生成叶子。因此,生成器的“大小”是生成树高度的上限,确保生成器在某个点终止并且不会生成过大的树。
请注意,在此示例中,大小仅为树的高度设置了 上限 。它不影响生成树的平衡或生成具有一定深度的树的可能性。这些仅取决于
genTree
中定义的偏差。使用
oneOf
,每个子树都有 50% 的机会成为叶子,在这个分支结束树的生长,这使得生成一棵用尽“整个”大小的完整树有点不太可能。frequency
(见下文)让你编码不同的偏差。在下面的例子中,节点比叶子更有可能,所以下面的生成器生成的树更有可能生长,但它仍然不太可能是完整的。与发电频率的关系
Gen.frequency
用于不同的用例:您不会使用它来限制数据结构的深度或大小,而是为生成器的选择添加一定的偏差。看一下 Gen.option
的定义:def option[T](g: Gen[T]): Gen[Option[T]] =
frequency(1 -> const(None), 9 -> some(g))
此定义使用
frequency
使 None
不太有趣的情况比 Some
更有趣的情况更不可能。事实上,我们可以在上面的二叉树示例中结合
Gen.sized
和 Gen.frequency
使 genTree
更有可能生成“有趣”的节点而不是“无聊”的叶子:def genTree: Gen[Tree] = Gen.sized { height =>
if (height <= 0) {
genLeaf
} else {
Gen.frequency(1 -> genLeaf, 9 -> genNode)
}
}
关于scala - 理解 ScalaChecks 的 'generation size',我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42834516/