I am learning Haskell and recently worked on a small project to mimic arithmetics in the way how human does it, ultimately I can keep as many decimal places as I want and computation results are not subject to the float precision issue. I also tried to use QuickCheck
to test against my program. The issue I have is that when I run QuickCheck, sometimes it can get very slow, takes very long to run and uses up a lot of CPU power.
The program is really long now so I will try to pick the most relevant lines and rearrange there down below:
data D
= D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9
deriving (Enum, Bounded, Eq, Ord, Show)
newtype N = N { getDs :: [D] }
nFromList :: [D] -> N
-- drops leading zeros and make an N value
instance Enum N where
-- implementation omitted here --
instance Eq N where
-- implementation omitted here --
instance Ord N where
-- implementation omitted here --
instance Num N where
-- implementation omitted here --
-- this is a fraction data, numerator/denominator/sign
data F = F N N Bool
getDenom :: F -> N
getDenom (F _ d _) = d
-- I can make data F a record but this was written long ago.
-- And the test case for this runs slowly.
instance Arbitrary D where
arbitrary = elements [minBound .. maxBound]
instance Arbitrary N where
arbitrary = do
l <- getSize ---------- impl#1 fast QuickCheck run
-- l <- choose (0, 10) :: Get Int --------- impl#2 slow QuickCheck run
ds <- replicateM l arbitrary
return $ nFromList ds
instance Arbitrary F where
arbitrary = do
num <- arbitrary
denom <- arbitrary
sign <- arbitrary
let denom' = max denom 1
return $ constructF num denom' sign
constructF :: N -> N -> Bool -> F
-- it does some validation on denominator and also reduce the fraction etc.
prop_PosDenom :: F -> Bool
prop_PosDenom f = (getDenom f) > 0
main = do
quickCheck prop_PosDenom
The issue is, in instance Aribtrary N
definition, if I use impl#1, everything works out great. The test cases take less than 1 second to run. But if I use impl#2, it would get randomly hung up at different point and it would take very long time to run, with 100% CPU usage for that core.
I tried to use Debug.Trace
and uses it everywhere but it doesn't look like it is somewhere in my code. It appears that somehow quickCheck generates two arbitrary F
values but there is delay to call prop_PosDenom.
Thank you in advance for any suggestions.