带有动态元素集的 QuickCheck

QuickCheck with Dynamic Element Sets

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

例如,假设以下数据类型:

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,因为 "arbitrary" 不接受这样的参数...

当生成器不需要任何上下文时,

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 ()