简体   繁体   中英

Testing QuickCheck properties against multiple types?

I have a type class Atomic , which defines functions for converting certain types to/from a wrapper value ( Atom ). I'd like to define a QuickCheck property which states: "for all instances of Atomic , any value may be stored and retrieved safely". The property looks like this:

class Atomic a where
    toAtom :: a -> Atom
    fromAtom :: Atom -> Maybe a

prop_AtomIdentity x = fromAtom (toAtom x) == Just x

However, if I just try to run that property through QuickCheck, it just picks one instance ( Bool ) and tests it. I'm currently working around that by defining type signatures for each supported atomic type in the test list, but this is verbose and error-prone:

containerTests =
    [ run (prop_AtomIdentity :: Bool -> Bool)
    , run (prop_AtomIdentity :: Word8 -> Bool)
    , run (prop_AtomIdentity :: String -> Bool)
    {- etc -} ]

I'm trying to define a function which will do this automatically:

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

But it fails with a typecheck error:

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)]

Is there a better way to test a QC property against multiple types? If not, can forallAtoms be made to work or is that not supported by the type system?

I cannot compile your code, so ... blind shot:

try

forallAtoms :: (forall a. (Atomic a, Show a) => a -> Bool) -> [TestOptions -> IO TestResult]

as a type signature. This needs the -XRankNTypes language extension.

The problem you have, as I see it, is that GHC tries to find one type to insert for a in x :: (a -> Bool) for the entire function scope, but you already give three different there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM