为什么在scalacheck中需要任意仲裁者? [英] Why do you need Arbitraries in scalacheck?

查看:92
本文介绍了为什么在scalacheck中需要任意仲裁者?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道为什么需要任意设置,因为自动属性测试需要属性定义,例如

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))

要获得对您自己的类型T的支持,您需要定义一个隐式def 或任意类型[T]的val.使用工厂方法Arbitrary(...) 创建任意实例.该方法采用一个类型的参数 Gen [T],并返回Arbitrary [T]的实例.

To get support for your own type T you need to define an implicit def or val of type Arbitrary[T]. Use the factory method Arbitrary(...) to create the Arbitrary instance. This method takes one parameter of type Gen[T] and returns an instance of Arbitrary[T].

它清楚地表明,我们需要Gen之上的任意性.但是,任意性的辩解并不令人满意

It clearly says that we need Arbitrary on top of Gen. Justification for arbitrary is not satisfactory, though

任意生成器是ScalaCheck在其生成时使用的生成器 生成属性参数的值.

The arbitrary generator is the generator used by ScalaCheck when it generates values for property parameters.

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中需要任意仲裁者?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆