Here is a simple function. It takes an input Int and returns a (possibly empty) list of pairs (Int, Int) , where the input Int is the sum of the cubic elements of any of the pairs.
cubeDecomposition :: Int -> [(Int, Int)] cubeDecomposition n = [(x, y) | x <- [1..m], y <- [x..m], x^3 + y^3 == n] where m = truncate $ fromIntegral n ** (1/3) -- cubeDecomposition 1729 -- [(1,12),(9,10)]
I want to check the property that the above is true; if I cube each element and summarize any tuple returned, then I return my input:
import Control.Arrow cubedElementsSumToN :: Int -> Bool cubedElementsSumToN n = all (== n) d where d = map (uncurry (+) . ((^3) *** (^3))) (cubeDecomposition n)
For runtime reasons, I would like to limit the input of Int to a certain size when checking this with QuickCheck. I can determine the appropriate type and instance of Arbitrary :
{-
And then, I think, I need to determine the versions of the function and properties that use SmallInt , not Int :
cubeDecompositionQC :: SmallInt -> [(SmallInt, SmallInt)] cubeDecompositionQC n = [(x, y) | x <- [1..m], y <- [x..m], x^3 + y^3 == n] where m = truncate $ fromIntegral n ** (1/3) cubedElementsSumToN' :: SmallInt -> Bool cubedElementsSumToN' n = all (== n) d where d = map (uncurry (+) . ((^3) *** (^3))) (cubeDecompositionQC n) -- cubeDecompositionQC 1729 -- [(SmallInt 1,SmallInt 12),(SmallInt 9,SmallInt 10)]
This works great, and the standard 100 tests pass as expected. But it seems there is no need to define a new type, instance, and function when I really need a special generator. So I tried this:
smallInts :: Gen Int smallInts = choose (-10000000, 10000000) cubedElementsSumToN'' :: Int -> Property cubedElementsSumToN'' n = forAll smallInts $ \m -> all (== n) (dm) where d = map (uncurry (+) . ((^3) *** (^3))) . cubeDecomposition
Now, the first few times that I ran this, everything worked fine, and all the tests pass. But in subsequent episodes, I observed setbacks. A reliable test size reliably finds one:
*** Failed! Falsifiable (after 674 tests and 1 shrink): 0 8205379
I got a little confused here due to having two abbreviated inputs - 0 and 8205379 - returned from QuickCheck, where I would intuitively expect it. In addition, these inputs work as predicted (in my indicative quality, at least):
*Main> cubedElementsSumToN 0 True *Main> cubedElementsSumToN 8205379 True
So it seems that there is a problem in the property that uses the custom Gen that I defined.
What I did wrong?