如何使用SmallCheck在Haskell? [英] How to use SmallCheck in 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 tosmallCheck
that the valid values areDwarf 1
throughDwarf 7
(orSnowWhite
)? What if I have a complicatedFairyTale
data structure and a constructormakeTale :: [Person] -> FairyTale
, and I wantsmallCheck
to make FairyTale-s from lists of Person-s using the constructor?
我设法让快速检查
这样的工作没有得到我的手太脏使用 Control.Monad.liftM $ C的明智应用$ C>像
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 Person
s? 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 Person
s 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>进制的功能
与串口
实例给串口值code>的
结果实例
。所以我们用它来创建[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 Person
s 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 Person
s, 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屋!