Тестирование свойств QuickCheck на нескольких типах?
-
11-09-2019 - |
Вопрос
У меня есть тип class Atomic
, который определяет функции для преобразования определенных типов в / из значения- оболочки (Atom
).Я хотел бы определить свойство QuickCheck, которое гласит:"для всех случаев Atomic
, любое значение может быть безопасно сохранено и извлечено".Свойство выглядит следующим образом:
class Atomic a where
toAtom :: a -> Atom
fromAtom :: Atom -> Maybe a
prop_AtomIdentity x = fromAtom (toAtom x) == Just x
Однако, если я просто попытаюсь запустить это свойство через QuickCheck, оно просто выберет один экземпляр (Bool
) и проверяет это.В настоящее время я работаю над этим, определяя сигнатуры типов для каждого поддерживаемого атомарного типа в списке тестов, но это многословно и подвержено ошибкам:
containerTests =
[ run (prop_AtomIdentity :: Bool -> Bool)
, run (prop_AtomIdentity :: Word8 -> Bool)
, run (prop_AtomIdentity :: String -> Bool)
{- etc -} ]
Я пытаюсь определить функцию, которая будет делать это автоматически:
forallAtoms :: (Atomic a, Show a) => (a -> Bool) -> [TestOptions -> IO TestResult]
forallAtoms x =
[ run (x :: Bool -> Bool)
, run (x :: Word8 -> Bool)
, run (x :: String -> Bool)
{- etc -} ]
containerTests = forallAtoms prop_AtomIdentity
Но это завершается неудачей с ошибкой проверки типа:
Tests/Containers.hs:33:0:
Couldn't match expected type `Word8' against inferred type `String'
In the first argument of `run', namely `(x :: Word8 -> Bool)'
In the expression: run (x :: Word8 -> Bool)
In the expression:
[run (x :: Bool -> Bool), run (x :: Word8 -> Bool),
run (x :: String -> Bool)]
Есть ли лучший способ протестировать свойство QC на нескольких типах?Если нет, можно ли заставить forallAtoms работать или это не поддерживается системой типов?
Решение
Я не могу скомпилировать ваш код, так что ...выстрел вслепую:
попробуй
forallAtoms :: (forall a. (Atomic a, Show a) => a -> Bool) -> [TestOptions -> IO TestResult]
в качестве подписи типа.Для этого требуется языковое расширение -XRankNTypes.
Проблема, с которой вы столкнулись, как я вижу, заключается в том, что GHC пытается найти один тип для вставки для a
в x :: (a -> Bool)
для всей области действия функции, но вы уже указываете там три разных.