如何使用SmallCheck在Haskell? [英] How to use SmallCheck in Haskell?

查看:137
本文介绍了如何使用SmallCheck在Haskell?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用 SmallCheck 测试一个Haskell程序,但我不知道如何使用该库来测试我自己数据类型。很显然,我需要使用Test.SmallCheck.Series.不过,我觉得它的文档极其混乱。我感兴趣的是两个食谱式的解决方案和逻辑(一元?)结构的理解解释。这里有一些问题我已经(所有相关的):

I am trying to use SmallCheck to test a Haskell program, but I cannot understand how to use the library to test my own data types. Apparently, I need to use the Test.SmallCheck.Series. However, I find the documentation for it extremely confusing. I am interested in both cookbook-style solutions and an understandable explanation of the logical (monadic?) structure. Here are some questions I have (all related):


  • 如果我有一个数据类型数据的人=雪白|矮人整数,我怎么向 smallCheck 的有效值为解释矮1 通过矮人7 (或雪白)?如果我有一个复杂的童话的数据结构和构造 makeTale :: [人] - >童话,我想 smallCheck 从使用构造人-S的名单让童话-S?

  • If I have a data type data Person = SnowWhite | Dwarf Integer, how do I explain to smallCheck that the valid values are Dwarf 1 through Dwarf 7 (or SnowWhite)? What if I have a complicated FairyTale data structure and a constructor makeTale :: [Person] -> FairyTale, and I want smallCheck to make FairyTale-s from lists of Person-s using the constructor?

我设法让快速检查这样的工作没有得到我的手太脏使用 Control.Monad.liftM makeTale 功能。我无法想出一个办法与 smallCheck 来做到这一点(请解释给我!)。

I managed to make quickCheck work like this without getting my hands too dirty by using judicious applications of Control.Monad.liftM to functions like makeTale. I couldn't figure out a way to do this with smallCheck (please explain it to me!).

什么是类型之间的关系串口系列等。

What is the relationship between the types Serial, Series, etc.?

(可选)是什么 coSeries 的地步?我如何使用 SmallCheck.Series

(optional) What is the point of coSeries? How do I use the Positive type from SmallCheck.Series?

(可选)的背后是什么什么应该是一元的前pression逻辑,什么是只是一个普通的功能,smallCheck的背景下任何澄清,将AP preciated。

(optional) Any elucidation of what is the logic behind what should be a monadic expression, and what is just a regular function, in the context of smallCheck, would be appreciated.

如果有没有任何前奏/教程使用 smallCheck ,我AP preciate的链接。非常感谢你!

If there is there any intro/tutorial to using smallCheck, I'd appreciate a link. Thank you very much!

更新:我要补充的是,最有用,最可读的文档,我发现了 smallCheck 是的本文(PDF)。我找不到答案我的问题上的第一个样子;它更是一个有说服力的广告比教程。

UPDATE: I should add that the most useful and readable documentation I found for smallCheck is this paper (PDF). I could not find the answer to my questions there on the first look; it is more of a persuasive advertisement than a tutorial.

更新2:我提出了我对怪异身份,在类型显示出来的问题 Test.SmallCheck .LIST 等地一<一href=\"http://stackoverflow.com/questions/16557610/why-does-smallchecks-series-class-have-two-types-in-the-constructor-what-is\">separate问题。

UPDATE 2: I moved my question about the weird Identity that shows up in the type of Test.SmallCheck.list and other places to a separate question.

推荐答案

注意:这个答案说明pre-1.0版本SmallCheck的。请参见这个博客帖子为SmallCheck 0.6和1.0之间的重要区别。

NOTE: This answer describes pre-1.0 versions of SmallCheck. See this blog post for the important differences between SmallCheck 0.6 and 1.0.

SmallCheck就像快速检查在于它测试超过可能的类型的空间的一些部分的性质。不同的是,它试图穷举小的价值观一系列的所有的短小而不是值任意子集。

SmallCheck is like QuickCheck in that it tests a property over some part of the space of possible types. The difference is that it tries to exhaustively enumerate a series all of the "small" values instead of an arbitrary subset of smallish values.

当我暗示,SmallCheck的串口就像是快速检查的任意

As I hinted, SmallCheck's Serial is like QuickCheck's Arbitrary.

现在串口是pretty简单:串口键入 A 有办法(系列)来生成一个系列键入这仅仅是一个函数从深度 - &GT; [A] 。或者,要解开的是,串口的对象是我们知道如何枚举的一些小值的对象。我们也给它控制,我们应该有多少小的值产生,但让我们忽略了一分钟一深度参数。

Now Serial is pretty simple: a Serial type a has a way (series) to generate a Series type which is just a function from Depth -> [a]. Or, to unpack that, Serial objects are objects we know how to enumerate some "small" values of. We are also given a Depth parameter which controls how many small values we should generate, but let's ignore it for a minute.

instance Serial Bool where series _ = [False, True]
instance Serial Char where series _ = "abcdefghijklmnopqrstuvwxyz"
instance Serial a => Serial (Maybe a) where
  series d = Nothing : map Just (series d)

在这种情况下,我们正在做的无非就是忽略了深度参数,然后对每种类型枚举所有可能的值更。我们甚至可以为某些类型的自动执行此操作。

In these cases we're doing nothing more than ignoring the Depth parameter and then enumerating "all" possible values for each type. We can even do this automatically for some types

instance (Enum a, Bounded a) => Serial a where series _ = [minBound .. maxBound]

这是试验性质的一个非常简单的方法,详尽,从字面上测试每一个可能的输入!显然,至少有两大缺陷,但:(1)无限的数据类型会导致无限循环测试和(2)的嵌套类型导致指数较大的例子空格翻阅时。在这两种情况下,SmallCheck变得非常大的真的很快。

This is a really simple way of testing properties exhaustively—literally test every single possible input! Obviously there are at least two major pitfalls, though: (1) infinite data types will lead to infinite loops when testing and (2) nested types lead to exponentially larger spaces of examples to look through. In both cases, SmallCheck gets really large really quickly.

所以这是深度的点参数 - 它让系统要求我们保持我们的系列小。从文档,深度

So that's the point of the Depth parameter—it lets the system ask us to keep our Series small. From the documentation, Depth is the

生成的测试值的最大深度

Maximum depth of generated test values

有关的数据值,它是嵌套构造应用的深度。

For data values, it is the depth of nested constructor applications.

有关的功能的值,它是巢式病例分析两者的深度和结果的深度。

For functional values, it is both the depth of nested case analysis and the depth of results.

让我们返工我们的例子中,让他们小。

so let's rework our examples to keep them Small.

instance Serial Bool where 
  series 0 = []
  series 1 = [False]
  series _ = [False, True]
instance Serial Char where 
  series d = take d "abcdefghijklmnopqrstuvwxyz"
instance Serial a => Serial (Maybe a) where
  -- we shrink d by one since we're adding Nothing
  series d = Nothing : map Just (series (d-1))

instance (Enum a, Bounded a) => Serial a where series d = take d [minBound .. maxBound]

好多了。

那么,什么是 coseries ?像 coarbitrary 任意类型类快速检查的,它让我们建立了一系列的小的功能。请注意,我们在输入型写作实例---结果类型是交给我们另一个串口参数(即我打电话以下结果)。

So what's coseries? Like coarbitrary in the Arbitrary typeclass of QuickCheck, it lets us build a series of "small" functions. Note that we're writing the instance over the input type---the result type is handed to us in another Serial argument (that I'm below calling results).

instance Serial Bool where
  coseries results d = [\cond -> if cond then r1 else r2 | 
                        r1 <- results d
                        r2 <- results d]

这需要一点多费心写,我会实际上是指你使用 ALTS 我将简要介绍如下方法。

these take a little more ingenuity to write and I'll actually refer you to use the alts methods which I'll describe briefly below.

那么,如何才能让取值一些系列?这部分很容易

So how can we make some Series of Persons? This part is easy

instance Series Person where
  series           d = SnowWhite : take (d-1) (map Dwarf [1..7])
  ...

但是,我们的 coseries 函数需要生成 s到别的一切可能的功能。这可以通过使用 altsN 一系列的SmallCheck提供的功能来完成。下面就来写一个办法

But our coseries function needs to generate every possible function from Persons to something else. This can be done using the altsN series of functions provided by SmallCheck. Here's one way to write it

 coseries results d = [\person -> 
                         case person of
                           SnowWhite -> f 0
                           Dwarf n   -> f n
                       | f <- alts1 results d ]

其基本思想是, altsN结果生成一个系列 N ňC $ C>进制的功能串口实例给串口结果实例。所以我们用它来创建[0..7],A ​​previously定义串口值的函数,到任何我们需要的,那么我们映射我们的 s到号码,并通过时间在

The basic idea is that altsN results generates a Series of N-ary function from N values with Serial instances to the Serial instance of Results. So we use it to create a function from [0..7], a previously defined Serial value, to whatever we need, then we map our Persons to numbers and pass 'em in.

所以,现在,我们已经为 A 串口例如,我们可以用它来构建更复杂的嵌套串口实例。对于实例,如果童话 s的列表,我们可以使用串行A =&GT;序号[A] 实例与我们的串行人实例能够轻松地创建一个系列童话

So now that we have a Serial instance for Person, we can use it to build more complex nested Serial instances. For "instance", if FairyTale is a list of Persons, we can use the Serial a => Serial [a] instance alongside our Serial Person instance to easily create a Serial FairyTale:

instance Serial FairyTale where
  series = map makeFairyTale . series
  coseries results = map (makeFairyTale .) . coseries results

(即(makeFairyTale。)撰写 makeFairyTale 与各功能 coseries 生成,这是一个有点混乱)

(the (makeFairyTale .) composes makeFairyTale with each function coseries generates, which is a little confusing)

这篇关于如何使用SmallCheck在Haskell?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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