【问题标题】:QuickCheck with Dynamic Element Sets使用动态元素集进行 QuickCheck
【发布时间】:2018-09-07 11:43:11
【问题描述】:

有没有办法以编程方式控制在任意定义内的元素调用中使用的值集?我希望能够生成任意变量引用作为随机表达式的一部分,但可供选择的变量标识符集应该是可配置的。

例如,想象以下数据类型:

data Expr = Num   Int
          | Var   String
          | BinOp Op Expr Expr

data Op = Add | Sub | Mul | Div deriving (Eq, Ord, Enum)

然后我想为这种类型定义一个任意实例,看起来像这样:

instance Arbitrary Op where
  arbitrary = elements [Add .. ]

instance Arbitrary Expr where
  arbitrary = oneof [ fmap Num arbitrary
                    , arbitraryBinOp
                    , fmap Var (elements varNames)
                    ]

arbitraryBinOp = do (op, e0, e1) <- arbitrary
                    return (BinOp op e0 e1)

现在棘手的是“varNames”部分。从概念上讲,我希望能够做这样的事情:

do args  <- getArgs
   tests <- generate $ vectorOf 10 ((arbitrary args)::Gen Expr)

但显然我不能通过任意调用向下传播该 args-vector,因为“任意”不接受这样的参数...

【问题讨论】:

    标签: haskell functional-programming quickcheck


    【解决方案1】:

    Arbitrary 实际上只是在生成器不需要任何上下文时才提供便利。如果您需要参数化您的生成器,您可以将它们定义为常规函数,并且 QuickCheck 具有组合器来使用此类显式生成器而不是 Arbitrary 实例。

    genExpr :: [String] -> Gen Expr
    genExpr varNames =
        oneof [ fmap Num arbitrary
              , arbitraryBinOp
              , fmap Var (elements varNames)
              ]
    
    main :: IO ()
    main = do
        args <- getArgs
        tests <- generate $ vectorOf 10 (genExpr args)
        {- do stuff -}
        return ()
    

    【讨论】:

    • 是的,这就是我一直在使用的方法。但是 Arbitrary 类非常方便 :-) 尤其是它为标准容器类型(如 Maybe、元组和列表)提供了开箱即用的生成器。我希望有一些不错的技巧可以用来将上下文添加到 Gen-monad 或其他东西。但我想我会继续我目前的道路。
    • @ØysteinKolsrud 好吧,你可以使用 monad 转换器:定义 type MyGen = ReaderT MyConfig Gen 然后你可以定义一个 MyArbitrary 类,并使用 @987654328 使 Arbitrary 的任何实例成为 MyArbitrary 的实例@ 作为实现。
    猜你喜欢
    • 2018-02-16
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 2016-11-13
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    相关资源
    最近更新 更多