是否有一种方法可以以编程方式控制要在任意定义内的元素调用中使用的值集?我希望能够生成随机变量引用作为随机表达式的一部分,但是要选择的变量标识符集应该是可配置的。
例如,设想以下数据类型:
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向下传播,因为“任意”不接受这种说法...
答案 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 ()