【问题标题】:How to generate specific random string in QuickCheck?如何在 QuickCheck 中生成特定的随机字符串?
【发布时间】:2019-09-09 19:01:40
【问题描述】:

在 Haskell 的 QuickCheck 中,如何生成一个只包含字符‘S’和‘C’的字符串,并且‘S’和‘C’的位置是随机的?

例如:“SCCS”、“SSSS”、“CCCC”、“CSSCCS”、“”

我的用例是这样的:

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

【问题讨论】:

    标签: haskell quickcheck


    【解决方案1】:

    让您的属性获取布尔值列表并将它们转换为 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
    

    【讨论】:

      【解决方案2】:

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

      prop_CountersEqual = 
        forAll csString $ \s -> countCAndS s == countCAndS' s
      
      csString :: Gen String
      csString = listOf $ elements "CS"
      

      如果你需要的话,扩展你的字典也很简单。

      【讨论】:

      • 谢谢。我更喜欢你的解决方案。感觉非常优雅,并且具有了解其工作原理所需的最少知识。
      【解决方案3】:

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

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

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

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

      如果字符串应该接受包含'C's 和'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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-29
        • 2021-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-13
        • 2010-09-10
        相关资源
        最近更新 更多