Testen Quick Check Eigenschaften gegen mehrere Typen?
-
11-09-2019 - |
Frage
Ich habe eine Typklasse Atomic
, die Funktionen für die Umwandlung von bestimmten Typen zu / von einem Wrapper-Wert (Atom
) definiert. Ich möchte einen Quick Check-Eigenschaft definieren, in dem es heißt: „für alle Instanzen Atomic
kann jeder beliebige Wert sicher gespeichert und abgerufen werden“. Die Eigenschaft sieht wie folgt aus:
class Atomic a where
toAtom :: a -> Atom
fromAtom :: Atom -> Maybe a
prop_AtomIdentity x = fromAtom (toAtom x) == Just x
Allerdings, wenn ich versuche gerade diese Eigenschaft durch Quick Check zu laufen, es nimmt nur eine Instanz (Bool
) und Tests es. Ich arbeite zur Zeit um die durch für jeden unterstützten Atomtyp in der Testliste Typen Signaturen definiert, aber dies ist ausführlich und fehleranfällige:
containerTests =
[ run (prop_AtomIdentity :: Bool -> Bool)
, run (prop_AtomIdentity :: Word8 -> Bool)
, run (prop_AtomIdentity :: String -> Bool)
{- etc -} ]
Ich versuche, eine Funktion zu definieren, die dies automatisch tun:
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
Aber es scheitert mit einem typecheck Fehler:
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)]
Gibt es einen besseren Weg, um eine QC Eigenschaft gegen mehrere Typen zu testen? Wenn nicht, kann forallAtoms gemacht werden, um zu arbeiten, oder ist das nicht vom Typ System unterstützt?
Lösung
Ich kann den Code nicht kompilieren, so ... Blindschuss:
Versuch
forallAtoms :: (forall a. (Atomic a, Show a) => a -> Bool) -> [TestOptions -> IO TestResult]
als eine Art Signatur. Dies muss die -XRankNTypes Spracherweiterung.
Das Problem, das Sie haben, wie ich es sehe, ist, dass GHC zu finden versucht, ein Typ für a
in x :: (a -> Bool)
für den gesamten Funktionsumfang einzusetzen, aber man bereits drei verschiedene dort geben.