QuickCheck с динамическими наборами элементов - PullRequest
0 голосов
/ 07 сентября 2018

Есть ли способ программно управлять набором значений для использования в вызове элементов в произвольном определении? Я хочу иметь возможность генерировать произвольную ссылку на переменную как часть случайного выражения, но набор идентификаторов переменных для выбора должен быть настраиваемым.

В качестве примера представим следующий тип данных:

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)

Но, очевидно, я не могу распространить этот аргумент-вектор через произвольные вызовы, так как «произвольный» не принимает такой аргумент ...

1 Ответ

0 голосов
/ 07 сентября 2018

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