1

I have the following Haskell functions:

  expM ::  Integer -> Integer -> Integer -> Integer
  expM x y = rem (x^y)

And

  exMME :: Integer -> Integer -> Integer -> Integer
  exMME b 0 m = 1
  exMME b e m = exMME' b e m 1 0 where    
    exMME' b e m c e'        
      | e' < e = exMME' b e m ((b * c) `mod` m) (e'+1)
      | otherwise = c

What I want to do is use quickCheck to compare these two functions so i can see that they produce the same answer and which one is the fastest.

To test if they have the same answers I want to let QuickCheck create random positive integers with the exception of 0. So I created a Gen:

positives :: Gen Integer
  positives = 
    do -- Pick an arbitrary integer:
      x <- arbitrary    
      if (x == 0) 
        then return 1
      else if (x < 0)
        then return (-x)
      else 
        return x

This works from the command line (ghci) but I have a prop:

  prop_CompareAnswerExMFM :: Integer -> Integer -> Integer -> Bool
  prop_CompareAnswerExMFM b e m =exMFM b e m == exM b e m

And each time i call this with QuickCheck prop_CompareAnswerExMFM it doesn't us my gen. After reading some stuff i toughed that i needed to define a instance:

  instance Arbitrary Integer where
    arbitrary = positives

This doesn't work because a arbitrary instance of Integer already exist. Again after some googling I say that the standard way to solve this is to use a wrapper:

  newtype Positives = Positives Integer
    deriving (Eq, Ord, Show)

  instance Arbitrary Positives where
    arbitrary = positives

  positives :: Gen Positives
  positives = 
    do -- Pick an arbitrary integer:
      x <- arbitrary    
      if (x == 0) 
        then return 1
      else if (x < 0)
        then return (-x)
      else 
        return x

But after playing around i keep getting errors like can't resolve this, No instance for (Num Positives) arising from the literal '0' or Can't make a derived instance of 'Num Positives'.

I think i'm making it way to complex for what i want but I just can't figure it out. I hope someone can help me or send me in the right direction.

Thanks

Phaeton
  • 79
  • 8
  • 1
    you already have this in `quickcheck`: [Positive](https://hackage.haskell.org/package/QuickCheck-2.8.1/docs/Test-QuickCheck-Modifiers.html#v:Positive) ... of course you should use it like this: `prop :: Positive -> Bool` and then `prop (Positive n) = ...` (deconstruct it with patternmatching to get out the number itself!) - or use `getPositive` inside your property to get the number – Random Dev Oct 11 '15 at 10:17
  • @carsten thanks i made it work using the tips you gave me. – Phaeton Oct 11 '15 at 17:00

2 Answers2

3

The problem with your code is that in positives the variable x has type Integer, so your return statements need to include the Positives constructor:

positives :: Gen Positives
positives =
   do -- Pick an arbitrary integer:
     x <- arbitrary
     if (x == 0)
       then return $ Positives 1
     else if (x < 0)
       then return $ Positives (-x)
     else
       return $ Positives x

If it helps, here is another way to write (a similarly working) positives function:

positives' :: Gen Positives
positives' = fmap (\x -> Positives (1 + abs x)) arbitrary

Here the arbitrary call is a Gen Integer, so the function argument to fmap has type Integer -> Positives.

To use your Positives newtype with QuickCheck you would use the Positives (de-)constructor to get at the Integer values:

prop_addition :: Positives -> Positives -> Bool
prop_addition (Positives a) (Positives b) = a + b >= 2

ghci> quickCheck prop_addtion

As @Carsten mentions in the comments, QuickCheck as a Positive a type which has an arbitrary instance for numeric and ordered types a.

ErikR
  • 51,541
  • 9
  • 73
  • 124
  • thanks I did change the Gen Integer to Gen Positives but did not realize i had to change x as well. I dropped the idea of using my own gen and thanks to the tips from @Carsten got it to work. – Phaeton Oct 11 '15 at 17:05
0

Here's a quick way that doesn't require much understanding of QuickCheck but is a bit of a hack:

prop_CompareAnswerExMFM :: Integer -> Integer -> Integer -> Bool
prop_CompareAnswerExMFM b e m =
   exMFM absB absE absM == exM absB absE absM
   where -- following guarantees args are positive integers > 0
      absB = 1 + abs b
      absE = 1 + abs e
      absM = 1 + abs m

and then you can just use

quickCheck prop_factored
George Co
  • 961
  • 6
  • 9