具有动态元素集的快速检查

时间:2018-09-07 11:43:12

标签: haskell functional-programming quickcheck

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

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

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向下传播,因为“任意”不接受这种说法...

1 个答案:

答案 0 :(得分:2)

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