factors :: Integer -> [Integer]The first lesson I learned along the way is that the result of a QuickCheck test is a Property, not a Bool; just a heads-up for other newbies. BTW, one of my favorite things about Real World Haskell is that it gives more than a passing thought to stuff like Cabal and QuickCheck.
factors x
| x < 2 = [1] | otherwise = sort $ factors' x 2 [1,x]
factors' :: Integer -> Integer -> [Integer] -> [Integer]
factors' x y zs
| fromInteger y > (sqrt $ fromInteger x) = zs
| x `mod` y == 0 && y*y /= x =
factors' x (y+1) (y : x `div` y : zs)
| x `mod` y == 0 && y*y == x =
factors' x (y+1) (y : zs)
| otherwise = factors' x (y+1) zs
The test machinery was rather more involved than the code itself. First I had to put together a list of prime numbers, then I could write code that would test factorization over primes and over products of two primes.
sieve :: Integral a => [a] -> [a]sieve (p:xs) = p : sieve [x | x <- xs, 0 /= x `mod` p] primes :: Integral a => [a]primes = sieve [2..]
primesInteger = primes :: [Integer]
This is all straightforward. Getting the final piece of test code took rather more time, but it refactored down togetPrime x = primesInteger !! (x `mod` 100)
buildAssocList :: Integral a => [a] -> [a] -> [a]buildAssocList xs ys = sort $ nub [a*b|a <- xs,b <- ys]
propAssoc x y = x > 0 ==> y > 0 ==>factors (x*y) == buildAssocList (factors x)
(factors y)
propPrime x = x > 0 ==>let prime = getPrime x in factors prime == [1,prime]
propSimple x y = x > 0 ==> y > 0 ==>let primeX = getPrime xprimeY = getPrime yin (factors $ primeX * primeY) ==
(sort $ nub [1,primeX,primeY,primeX*primeY])
This works, though I've got to say that the prop_complex check on the length of zs is not exactly elegant. I'd love to hear comments on how to make it more idiomatic Haskell (and that applies to all the code).testDepth = 8 -- actually N-1
check :: Integer -> [Integer] -> Integer -> [Integer] -> Boolcheck 0 _ _ _ = Truecheck y xs n ns =let p = getPrime (1 + abs(fromIntegral $ head xs))ps = factors pp_list = build_assoc_list ns psin factors (n*p) == p_list &&
check (y-1) (tail xs) (n*p) (p_list)
prop_complex z zs = z > 0 &&(fromIntegral $ length zs) >=
(fromIntegral (z `mod` testDepth)) ==>check (z `mod` testDepth) zs 1 [1]
No comments:
Post a Comment