I'm working through the wonderful Haskell Book. While solving some exercises I ran QuickCheck test that took a relatively long time to run and I can't figure out why.
The exercise I am solving is in Chapter 16 - I need to write a Functor
instance for
data Parappa f g a =
DaWrappa (f a) (g a)
Here is a link to the full code of my solution. The part I think is relevant is this:
functorCompose' :: (Eq (f c), Functor f)
=> Fun a b -> Fun b c -> f a -> Bool
functorCompose' fab gbc x =
(fmap g (fmap f x)) == (fmap (g . f) x)
where f = applyFun fab
g = applyFun gbc
type ParappaComp =
Fun Integer String
-> Fun String [Bool]
-> Parappa [] Maybe Integer
-- -> Parappa (Either Char) Maybe Integer
-> Bool
main :: IO ()
main = do
quickCheck (functorCompose' :: ParappaComp)
When I run this in the REPL it takes ~6 seconds to complete. If I change ParappaComp
to use Either Char
instead of []
(see comment in code), it finishes instantaneously like I'm used to seeing in all other exercises.
I suspect that maybe QuickCheck is using very long lists causing the test to take a long time, but I am not familiar enough with the environment to debug this or to test this hypothesis.
- Why does this take so long?
- How should I go about debugging this?
[]
is a list. An arbitrary list can have an arbitrary number of elements, so that means it can take some time to perform a mapping over the entire list. For anEither
, this is a single element. - Willem Van OnsemFun
s that accept lists, includingString
s, are very slow. Switch your intermediate type fromString
toChar
, and it completes quickly. - K. A. BuhrString
was the problem. I then testedFun
s with list arguments in isolation and saw that they performed quite poorly. - K. A. Buhr