Как создать произвольную функцию с двумя аргументами с помощью QuickCheck?

Я пытаюсь проверить свою реализацию zipWith с помощью QuickCheck. Моя реализация, myZipWith, я хотел бы протестировать QuickCheck, сравнив ее со стандартной функцией. Что-то типа:

main = do
  quickCheck (prop_myZipWith :: (Int -> Int -> Int) -> [Int] -> [Int] -> Bool)

prop_myZipWith :: (a -> b -> c) -> [a] -> [b] -> Bool
prop_myZipWith f x y = (myZipWith x y) == (zipWith f x y)

Это не работает, потому что (Int -> Int -> Int) не является экземпляром Arbitrary.

С помощью функций с одним аргументом это можно обойти, используя Test.QuickCheck.Function Fun (который создает экземпляр Arbitrary). Например:

main = do
  quickCheck (prop_myMap :: Fun Int Int -> [Int] -> Bool)

prop_myMap :: Fun a b -> [a] -> Bool
prop_myMap (Fun _ f) l = (myMap f l) == (map f l)

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

Как создать произвольные экземпляры функций с двумя аргументами для тестирования QuickCheck функций высшего порядка, таких как zipWith?


person mherzl    schedule 02.09.2017    source источник
comment
Разве вы не можете просто использовать каррирование и использовать Fun Int (Fun Int Int)? Помните, что не существует такой вещи, как бинарная функция, поскольку все содержит каррирование.   -  person chi    schedule 02.09.2017
comment
Обратите внимание, что оператор This не работает, потому что (Int -> Int -> Int) не является экземпляром Arbitrary. ложно (функции являются экземплярами Arbitrary). Это не работает, потому что функции не являются экземплярами Show. Но, как говорит @chi, каррирование решает вашу проблему тривиальным способом (а также лишь немного менее тривиальным способом, который также будет работать Fun (Int, Int) Int). Вы можете найти определения unFun (Fun _ f) = f; unFun2 f = unFun . unFun f полезными.   -  person user2407038    schedule 02.09.2017
comment
@chi, мой ограниченный практический опыт показывает, что Fun (a,b,...) x менее болезненно работать, чем Fun a (Fun b (... x ...))   -  person dfeuer    schedule 22.09.2017
comment
Если ваш следующий вопрос будет о функциях высшего порядка?, то это тоже был мой вопрос. Но это, кажется, очень сложно. Koen Claessen не смог найти удовлетворительного решения, поэтому его следует рассматривать только в том случае, если вам нужен исследовательский проект.   -  person dfeuer    schedule 22.09.2017


Ответы (1)


Быстрая проверка 2.9.2

В QuickCheck 2.9.2 можно использовать тип Fun и шаблон Fn. Вы должны будете

import Test.QuickCheck.Function

Затем вы можете написать свойство, используя кортеж в качестве входных данных, а затем curry функцию:

prop_myZipWith :: Eq c => Fun (a, b) c -> [a] -> [b] -> Bool
prop_myZipWith (Fn f) x y = myZipWith (curry f) x y == zipWith (curry f) x y

main выглядит так:

main =
  quickCheck (prop_myZipWith :: Fun (Int, Int) Int -> [Int] -> [Int] -> Bool)

Это компилируется, и тест проходит в моем репро.

Быстрая проверка 2.10.0.1

В QuickCheck 2.10.0.1 вы можете вместо этого использовать шаблон Fn2, например:

prop_myZipWith :: Eq c => Fun (a, b) c -> [a] -> [b] -> Bool
prop_myZipWith (Fn2 f) x y = myZipWith f x y == zipWith f x y

Основной метод остается прежним, потому что тип prop_myZipWith не изменился, а import Test.QuickCheck.Function больше не требуется.

person Mark Seemann    schedule 22.09.2017