我有以下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'的派生实例。
我认为我正在为我想要的东西复杂化,但我无法理解。我希望有人可以帮助我,或者让我朝着正确的方向前进。
谢谢
答案 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