在Haskell QuickCheck中,如何生成一个字符串,使其只包含字符'S'和'C','S'和'C'的位置是随机的?
例如," SCCS"," SSSS"," CCCC"," CSSCCS",""
我的用例是:我有两个函数countCAndS :: String -> (Int, Int)
,countCAndS' :: String -> (Int, Int)
。它们具有相同的类型签名。我想编写一个quickcheck属性,以便我可以将相同的字符串传递给这两个不同的函数,并检查输出是否相同。
答案 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