问题描述
我想知道为什么需要任意设置,因为自动属性测试需要属性定义,例如
I wonder why Arbitrary is needed because automated property testing requires property definition, like
val prop = forAll(v: T => check that property holds for v)
和值v生成器.用户指南说,您可以为自定义类型创建自定义生成器(以树生成器为例).但是,它并不能解释为什么您还需要仲裁员.
and value v generator. The user guide says that you can create custom generators for custom types (a generator for trees is exemplified). Yet, it does not explain why do you need arbitraries on top of that.
这是一本手册
implicit lazy val arbBool: Arbitrary[Boolean] = Arbitrary(oneOf(true, false))
它清楚地表明,我们需要Gen之上的任意性.但是,任意性的辩解并不令人满意
It clearly says that we need Arbitrary on top of Gen. Justification for arbitrary is not satisfactory, though
IMO,要使用生成器,您需要导入它们,而不是将它们包装到任意容器中!否则,有人可能会争辩说,我们还需要将任意仲裁程序包装到其他内容中以使它们可用(依此类推,无限循环地包装这些包装程序).
IMO, to use the generators, you need to import them rather than wrapping them into arbitraries! Otherwise, one can argue that we need to wrap arbitraries also into something else to make them usable (and so on ad infinitum wrapping the wrappers endlessly).
您还可以解释arbitrary[Int]
如何将参数类型转换为生成器.很好奇,我觉得这些是相关的问题.
You can also explain how does arbitrary[Int]
convert argument type into generator. It is very curious and I feel that these are related questions.
推荐答案
forAll { v: T => ... }
是在Scala implicits 的帮助下实现的.这意味着T
类型的生成器是隐式找到的,而不是由调用方显式指定的.
forAll { v: T => ... }
is implemented with the help of Scala implicits. That means that the generator for the type T
is found implicitly instead of being explicitly specified by the caller.
标量隐式函数很方便,但是如果您不确定当前范围内的隐式值或转换,它们也很麻烦.通过使用特定类型(Arbitrary
)进行隐式查找,ScalaCheck尝试限制使用隐式的负面影响(这种用法也使其类似于某些用户熟悉的Haskell typeclasses ).
Scala implicits are convenient, but they can also be troublesome if you're not sure what implicit values or conversions currently are in scope. By using a specific type (Arbitrary
) for doing implicit lookups, ScalaCheck tries to constrain the negative impacts of using implicits (this use also makes it similar to Haskell typeclasses that are familiar for some users).
因此,您完全正确地确实不需要Arbitrary
.通过隐式Gen[T]
值可以达到相同的效果,可以说是更多的隐式作用域范围混淆.
So, you are entirely correct that Arbitrary
is not really needed. The same effect could have been achieved through implicit Gen[T]
values, arguably with a bit more implicit scoping confusion.
作为最终用户,您应该将Arbitrary[T]
视为类型T
的默认生成器.您可以(通过作用域)定义和使用多个Arbitrary[T]
实例,但是我不建议这样做.相反,只需跳过Arbitrary
并明确指定生成器:
As an end-user, you should think of Arbitrary[T]
as the default generator for the type T
. You can (through scoping) define and use multiple Arbitrary[T]
instances, but I wouldn't recommend it. Instead, just skip Arbitrary
and specify your generators explicitly:
val myGen1: Gen[T] = ...
val mygen2: Gen[T] = ...
val prop1 = forAll(myGen1) { t => ... }
val prop2 = forAll(myGen2) { t => ... }
arbitrary[Int]
的工作方式与forAll { n: Int => ... }
相似,只是查找隐式的Arbitrary[Int]
实例并使用其生成器.实现很简单:
arbitrary[Int]
works just like forAll { n: Int => ... }
, it just looks up the implicit Arbitrary[Int]
instance and uses its generator. The implementation is simple:
def arbitrary[T](implicit a: Arbitrary[T]): Gen[T] = a.arbitrary
Arbitrary
的实现在这里也可能会有所帮助:
The implementation of Arbitrary
might also be helpful here:
sealed abstract class Arbitrary[T] {
val arbitrary: Gen[T]
}
这篇关于为什么在scalacheck中需要任意仲裁者?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!