{-# LANGUAGE TemplateHaskell #-} import Data.Integer.SAT import Test.QuickCheck import System.Exit instance Arbitrary BoundType where arbitrary = elements [Lower, Upper] withBounds :: Testable prop => BoundType -> [(Positive Integer, Integer)] -> (Integer -> prop) -> Property withBounds kind bs prop = counterexample (show (map toBound bs)) $ case iPickBounded kind (map toBound bs) of Nothing -> property Discard Just n -> counterexample (show n) (property (prop n)) where toBound (Positive c, t) = Bound c (tConst t) prop_lower, prop_upper :: [(Positive Integer, Integer)] -> Property prop_lower bs = withBounds Lower bs $ \n -> and [t < c * n | (Positive c, t) <- bs] && or [t >= c * (n-1) | (Positive c, t) <- bs] prop_upper bs = withBounds Upper bs $ \n -> and [c * n < t | (Positive c, t) <- bs] && or [c * (n+1) >= t | (Positive c, t) <- bs] -- This is so that the Template Haskell below can see the above properties. $(return []) main :: IO () main = do ok <- $(quickCheckAll) if ok then exitSuccess else exitFailure