如何在QuickCheck中生成特定的随机字符串?

时间:2018-04-09 17:09:17

标签: haskell quickcheck

在Haskell QuickCheck中,如何生成一个字符串,使其只包含字符'S'和'C','S'和'C'的位置是随机的?

例如," SCCS"," SSSS"," CCCC"," CSSCCS",""

我的用例是:我有两个函数countCAndS :: String -> (Int, Int)countCAndS' :: String -> (Int, Int)。它们具有相同的类型签名。我想编写一个quickcheck属性,以便我可以将相同的字符串传递给这两个不同的函数,并检查输出是否相同。

3 个答案:

答案 0 :(得分:6)

让您的财产获取布尔值列表并将其转换为cs和ss。

prop_CountersEqual :: [Bool] -> Bool
prop_CountersEqual bs = countCAndS css == countCAndS' css where
    css = map (\b -> if b then 'C' else 'S') bs

如果您经常需要此功能,则可能需要使用合适的Arbitrary实例定义新类型。

newtype CAndS = CAndS String
instance Arbitrary CAndS where
    arbitrary = CAndS . map (\b -> if b then 'C' else 'S') <$> arbitrary

然后你可以写下你的属性。

prop_CountersEqual' :: CAndS -> Bool
prop_CountersEqual' (CAndS css) = countCAndS css == countCAndS' css

答案 1 :(得分:2)

QuickCheck为此提供了一系列组合器,它非常简单而且非常优雅:

prop_CountersEqual = 
  forAll csString $ \s -> countCAndS s == countCAndS' s

csString :: Gen String
csString = listOf $ elements "CS"

如果你需要,扩展你的字典也是微不足道的。

答案 2 :(得分:0)

这是定义Arbitrary实例的另一种方法:

newtype CAndS = CAndS String
instance Arbitrary CAndS where
  arbitrary = CAndS <$> listOf (elements "CS")

除了针对参考解决方案测试函数之外,您还可以测试'C''S' es的总和与字符串的长度相同:

prop_CountersAddUp :: CAndS -> Bool
prop_CountersAddUp (CAndS css) = length css == cs + ss
  where (cs, ss) = countCAndS css

如果字符串应该接受包含'C''S' es之外的字符的输入(但不计算它们),那么您应该创建一个生成各种字符的生成器,但是'C''S'的概率较高:

newtype CAndS = CAndS String
instance Arbitrary CAndS where
  arbitrary = CAndS <$> listOf (frequency [ (1, return 'C')
                                          , (1, return 'S')
                                          , (2, arbitrary) ])

或者你可能会生成一个用正确答案注释的字符串:

newtype CAndS = CAndS (String, Int, Int)
instance Arbitrary CAndS where
    arbitrary = CAndS <$> sized (\n -> do
      cs <- choose (0, n)
      let ss = n - cs
      css <- shuffle (replicate cs 'C' ++ replicate ss 'S')
      return (css, cs, ss))

所以你可以测试一下:

prop_CountersEqual :: CAndS -> Bool
prop_CountersEqual (CAndS (css, cs, ss)) = cs == cs' && ss == ss'
  where (cs', ss') = countCAndS css