0

我有以下,创建“类型”

type Pos = (Int, Int) 

我要生成这种类型的随机值有一些限制(这两个必须是0-8)

我会的任意intance喜欢做类似

instance Arbitrary Pos where 
    arbitrary = do x <- choose(0,8) 
       y <- choose(0,8) 
       return (x,y) 

然后在我的测试中使用它有有效位置。

BC我走样这是不行的(?)元组

我试图

其他方法使用的影响在我的测试说

prop_my_prop (x,y) = abs x < 9 && abs y < 9 ==> ... 

,但我认为这是相当丑陋理论上它可能耗尽快速检测(超过1000次)。

这是一项任务,所以我只想要一些指示,看看或如何处理这个问题,我不允许更改Pos。

回答

2

唐斯图尔特的回答描述了可以说最好的方式来做到这一点。但是,如果由于某种原因你不想使用NEWTYPE可以按如下方式使用自定义生成器:

positionsToTest :: Gen Pos 
positionsToTest = do x <- choose (0,8) 
        y <- choose (0,8) 
        return (x,y) 

prop_myTest = forAll positionsToTest (\ pos -> myProperty pos) 

Runnung快速检查上prop_myTest应该做你想要什么。

6

BC我走样这是不行的(?)元组

是的,这是正确的。定义一个新的数据类型,你可以有一个新的实例。

data Pos = Pos Int Int 

newtype Pos = Pos (Int, Int) 

然后,你可以写出来与大家喜欢的任何发电机自己的任意实例。

+0

我不允许将类型Pos更改为数据Pos – skyw00lker 2014-10-09 14:10:18

+1

然后您必须将您的生成器编写为函数而不是类型的方法。 – 2014-10-09 14:20:43

3

好吧,如果你不能改变Posdatanewtype不管什么原因,你总是可以做到以下几点:与Arbitrary实例一起定义的包装

newtype PosA = PosA { unPosA :: Pos } deriving (Eq,Show) -- and whatever else you need! 

它:

instance Arbitrary PosA where 
    arbitrary = do x <- choose(0,8) 
       y <- choose(0,8) 
       return $ PosA (x,y) 

最后,重写你想要检查的所有命题,以便它们的类型不再提及Pos,而只是代替PosA。例如说你有一个功能mirror和镜像两次对身份属性:

mirror :: Pos -> Pos 
mirror (x,y) = (y,x) 

prop_mirror :: Pos -> Bool 
prop_mirror pos = mirror (mirror pos) == pos 

然后,你需要做prop_mirror_A,像这样

prop_mirror_A :: PosA -> Bool 
prop_mirror_A pos = prop_mirror (unPosA pos) 

(未经测试的代码!)而你正在参加比赛。你也许可以做一些从prop_mirror由聪明类型类巫术工作“提升”到prop_mirror_A的,但我不打算现在想想:-)

(顺便说一句,这是一个很好的理由键入同义词通常不是正确的选择!)