使用quickcheck比较两个函数以生成正整数

时间:2015-10-11 09:59:23

标签: haskell quickcheck

我有以下Haskell函数:

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

  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

我想要做的是使用quickCheck来比较这两个函数,这样我就可以看到它们产生相同的答案,哪一个是最快的。

为了测试他们是否有相同的答案我想让QuickCheck创建随机正整数,除了0。所以我创建了一个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

这可以从命令行(ghci)开始,但我有一个道具:

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

每次我使用QuickCheck prop_CompareAnswerExMFM调用它时,它不是我的天才。在读完一些东西后,我强调我需要定义一个实例:

  instance Arbitrary Integer where
    arbitrary = positives

这不起作用,因为已存在任意Integer实例。在一些谷歌搜索之后,我再说解决这个问题的标准方法是使用包装器:

  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

但在玩完之后我一直得到错误就像无法解决这个问题一样,没有(Num Positives)的实例来自字面上的'0'或者不能创建'Num Positives'的派生实例。

我认为我正在为我想要的东西复杂化,但我无法理解。我希望有人可以帮助我,或者让我朝着正确的方向前进。

谢谢

2 个答案:

答案 0 :(得分:3)

代码的问题在于positives变量x的类型为Integer,因此您的return语句需要包含Positives构造函数:

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

如果有帮助,这是另一种编写(类似工作)positives函数的方法:

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

此处arbitrary来电是Gen Integer,因此fmap的函数参数类型为Integer -> Positives

要在QuickCheck中使用Positives newtype,您可以使用Positives(de-)构造函数来获取Integer值:

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

ghci> quickCheck prop_addtion

正如@Carsten在评论中提到的那样,QuickCheck为Positive a类型,其中包含数字和有序类型的任意实例 a

答案 1 :(得分:0)

这是一种快速方法,不需要对QuickCheck有所了解,但有点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

然后您就可以使用

quickCheck prop_factored