0

I have the following,

type Pos = (Int, Int) 

I want to generate random values of this type with some restrictions (both has to be 0-8)

I would like to do something like

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

and then use it in my test to have valid positions.

This won't work bc I'm aliasing(?) tuples

other methods I have tried are to use implications in my test to say

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

but I think that's pretty ugly and in theory it might exhaust the quickchecktest (run over 1000 times).

this is an assignment so I just want some indication were to look or how to approach this, I'm not allowed to change Pos.

skyw00lker
  • 819
  • 9
  • 20

3 Answers3

6

This won't work bc I'm aliasing(?) tuples

Yes, that's correct. Define a new data type and you can have a new instance.

data Pos = Pos Int Int 

or

newtype Pos = Pos (Int, Int)

Then you can write your own Arbitrary instance with whatever generator you like.

Don Stewart
  • 137,316
  • 36
  • 365
  • 468
3

Well, if you can't change Pos to a data or newtype for whatever reason, you could always do the following: define a wrapper

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

along with an Arbitrary instance for it:

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

and finally, rewrite all the propositions you want to check so that their type no longer mentions Pos but only PosA instead. Say for example that you had a function mirror and the property that mirroring twice is the identity:

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

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

Then you'd need to make prop_mirror_A, something like this (untested code!)

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

and you're off to the races. You can probably do some of the work 'lifting' from prop_mirror to prop_mirror_A by Clever Typeclass Wizardry, but I'm not going to think about that now :-)

(Incidentally, this is a good reason why type synonyms are usually not the right choice!)

yatima2975
  • 6,580
  • 21
  • 42
2

Don Stewart's answer describes the arguably best way to do it. However, if for some reason you don't want to use a newtype you can use a custom generator as follows:

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

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

Runnung quickCheck on prop_myTest should do what you want.

DanielM
  • 1,023
  • 8
  • 18