I'm having a bit of trouble wrapping my mind around QuickCheck. Consider the following simple data type and it's corresponding arbitrary instance.
EDIT: Full code below as requested in a comment. fixedToFractional
converts fixed numeric types such as Micro
to Fractional
.
import Data.Fixed
import System.Random
import Control.Applicative
import Test.QuickCheck
fixedToFractional :: (HasResolution a, Fractional b) => Data.Fixed.Fixed a -> b
fixedToFractional = fromRational . toRational
instance Random Micro where
randomR (lo, hi) g = randomR (fixedToFractional lo, fixedToFractional hi) g
random g = randomR (-999999, 999999) g
data FooType = FooType { foo :: Micro } deriving (Show)
instance Arbitrary FooType where
arbitrary =
FooType <$> x
where
x = choose (0.0, 1.0)
If I understand things correctly, this should allow random FooType
values to be generated, with the foo
field set to a random value between 0 and 1.
Next, consider the following simple test.
prop_foo_is_gte_zero ft = (foo ft) >= 0.0
When I attempt to run the above test, whether in ghci, or in a test file using quickCheckAll
, the test never completes. ghc
eats up a few gigs of RAM in a matter of seconds, and will eventually run my machine out of swap space if I don't kill it. I'm probably missing something incredibly fundamental/stupid, but (obviously) don't know what. Any ideas?
EDIT: I am now questioning my Random
instance. Perhaps the problem is there and not with my Arbitrary
instance.
Seems you have an issue inside your Random
instance for Micro
Here is a quick hack to fix it:
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
import Data.Fixed
import System.Random
import Test.QuickCheck
toDouble :: Micro -> Double
toDouble = realToFrac . toRational
instance Random Micro where
randomR (lo, hi) g =
let (a,g') = randomR (toDouble lo, toDouble hi) g
in (fromRational (toRational a), g')
random = randomR (-999999, 999999)
data FooType = FooType { foo :: Micro } deriving (Show)
instance Arbitrary FooType where
arbitrary =
FooType <$> x
where
x = choose (0.0, 1.0)
main :: IO ()
main = quickCheck prop_foo_is_gte_zero
where prop_foo_is_gte_zero ft = foo ft >= 0.0