{-# LANGUAGE ScopedTypeVariables #-} module Hedgehog.Classes.Integral (integralLaws) where import Hedgehog import Hedgehog.Classes.Common -- | Tests the following 'Integral' laws: -- -- [__Quotient Remainder__]: @'quot' x y '*' y '+' ('rem' x y)@ ≡ @x@ -- [__Division Modulus__]: @('div' x y) '*' y '+' ('mod' x y)@ ≡ @x@ -- [__Integer Roundtrip__]: @'fromInteger' '.' 'toInteger'@ ≡ @'id'@ integralLaws :: (Integral a, Show a) => Gen a -> Laws integralLaws gen = Laws "Integral" [ ("Quotient Remainder", integralQuotientRemainder gen) , ("Division Modulus", integralDivisionModulus gen) , ("Integer Roundtrip", integralIntegerRoundtrip gen) ] integralQuotientRemainder :: forall a. (Integral a, Show a) => Gen a -> Property integralQuotientRemainder gen = property $ do x <- forAll gen y <- forAll gen let lhs = (quot x y) * y + (rem x y) let rhs = x let ctx = contextualise $ LawContext { lawContextLawName = "Quotient Remainder", lawContextTcName = "Integral" , lawContextLawBody = "quot x y * y + (rem x y)" `congruency` "x" , lawContextTcProp = let showX = show x; showY = show y; in lawWhere [ "quot x y * y + (rem x y)" `congruency` "x, where" , "x = " ++ showX , "y = " ++ showY ] , lawContextReduced = reduced lhs rhs } heqCtx lhs rhs ctx integralDivisionModulus :: forall a. (Integral a, Show a) => Gen a -> Property integralDivisionModulus gen = property $ do x <- forAll gen y <- forAll gen let lhs = (div x y) * y + (mod x y) let rhs = x let ctx = contextualise $ LawContext { lawContextLawName = "Division Modulus", lawContextTcName = "Integral" , lawContextLawBody = "(div x y) * y + (mod x y)" `congruency` "x" , lawContextTcProp = let showX = show x; showY = show y; in lawWhere [ "(div x y) * y + (mod x y)" `congruency` "x, where" , "x = " ++ showX , "y = " ++ showY ] , lawContextReduced = reduced lhs rhs } heqCtx lhs rhs ctx integralIntegerRoundtrip :: forall a. (Integral a, Show a) => Gen a -> Property integralIntegerRoundtrip gen = property $ do x <- forAll gen let lhs = fromInteger (toInteger x) let rhs = x let ctx = contextualise $ LawContext { lawContextLawName = "Integer Roundtrip", lawContextTcName = "Integral" , lawContextLawBody = "fromInteger . toInteger" `congruency` "id" , lawContextTcProp = let showX = show x; in lawWhere [ "fromInteger . toInteger $ x" `congruency` "id x, where" , "x = " ++ showX ] , lawContextReduced = reduced lhs rhs } heqCtx lhs rhs ctx