{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE ScopedTypeVariables #-} {-| This package has four ways to extend any numerical type to add infinities: 1. Both infinities with GADT: 'AffinelyExtendBoth', creation: 'affinelyExtendBoth' 2. Positive infinity only with GADT: 'AffinelyExtendPos', creation: 'affinelyExtendPos' 3. Both infinities with upper/lower bounds as infinity: 'AffinelyExtendBoundedBoth', creation: 'affinelyExtendBoundedBoth' 4. Positive infinities only with upper bound as infinity: 'AffinelyExtendBoundedPos', creation: 'affinelyExtendBoundedPos' The function 'affinelyExtend' is a generic creation function that calls one of the above based on the derived type of the output. A few notes. Firstly, option 3, the 'AffinelyExtendBoundedBoth' option, does not actually use 'maxBound' and 'minBound' as positive and negative infinity respectively, it actually takes the smallest absolute value 'maxBound' and 'minBound' as positive infinity and the negation of that as negative infinity. This means, for example, on an 'Int8', +127 is positive infinity, but -127 is negative infinity, not -128. So the valid finite range for the type becomes [-126..126]. Storable and unboxed instances for bounded types (i.e. 'AffinelyExtendBoundedBoth' and 'AffinelyExtendBoundedPos') should be trivial to create. This package refers to the first two types, namely 'AffinelyExtendBoth' and 'AffinelyExtendPos' as unpacked types. When they're used directly, packing and unpacking is just 'id', but when the bounded types are used, they are unpacked into these types and packed back into themselves. For most operations, the bounded types simply unpack to the unbounded types, perform the unpacked operation, and then pack themselves. But there's two optimisations to this process 1. For operations like 'negate', there is no need for special checking for infinities, so the unbounded types just apply negate directly to their own representation. 2. There's rewrite rules that remove 'unpack . pack' sequences. There's competing advantages to both formats. The bounded formats obviously take up less storage space, and can perform some operations like 'negate' without a pattern match. However, chains of operations on the "packed" bounded types that do need to check for infinity will check everytime, because there's no way for the compiler to disguish between and operation that has overflowed and "accidently" became infinity and actual infinity. So the rewrite rules are intended to help chains of operations use the "unpacked" represenation, which hopefully should reduce the infinity checks to the first operation in the sequence (as after that the compiler should be able to statically prove at compile time that the latter operations are/are not infinities. This package is currently without a test suite and needs more documentation, so if you find any bugs, please report them. -} module Data.AffinelyExtend ( AffinelyExtend(NegativeInfinity, Finite, PositiveInfinity), affinelyExtend, AffinelyExtendBoth, affinelyExtendBoth, AffinelyExtendPos, affinelyExtendPos, AffinelyExtendBoundedBoth, affinelyExtendBoundedBoth, AffinelyExtendBoundedPos, affinelyExtendBoundedPos, CanAffinelyExtend, isPos, isNegInf, isInf, isFinite, BaseType, UnpackType, affinelyExtend_c, unpack_c, unpackBoth_c, CanAffinelyExtendPos, unpackPos_c, HasPositiveInfinity, posInf, HasBothInfinities, negInf ) where import Control.Exception.Base (assert) import GHC.Exts (Constraint) import Data.Maybe (maybeToList) import Control.Applicative ((<|>)) data AffinelyExtend (hasNegativeInfinity :: Bool) a where NegativeInfinity :: AffinelyExtend True a Finite :: a -> AffinelyExtend h a PositiveInfinity :: AffinelyExtend h a type AffinelyExtendBoth a = AffinelyExtend True a type AffinelyExtendPos a = AffinelyExtend False a newtype AffinelyExtendBoundedBoth a = AffinelyExtendBoundedBoth { getAffinelyExtendBounded :: a } newtype AffinelyExtendBoundedPos a = AffinelyExtendBoundedPos { getAffinelyExtendBoundedPos :: a } class HasPositiveInfinity a where posInf :: a class HasPositiveInfinity a => HasBothInfinities a where negInf :: a unwrappedPosInf :: (Bounded a, Ord a, Num a) => a unwrappedPosInf = min maxBound (negate minBound) unwrappedNegInf :: (Bounded a, Ord a, Num a) => a unwrappedNegInf = negate unwrappedPosInf unwrappedPosInfPos :: (Bounded a) => a unwrappedPosInfPos = maxBound instance HasPositiveInfinity (AffinelyExtendBoth a) where posInf = PositiveInfinity instance HasBothInfinities (AffinelyExtendBoth a) where negInf = NegativeInfinity instance HasPositiveInfinity (AffinelyExtendPos a) where posInf = PositiveInfinity instance (Bounded a, Ord a, Num a) => HasPositiveInfinity (AffinelyExtendBoundedBoth a) where posInf = AffinelyExtendBoundedBoth unwrappedPosInf instance (Bounded a, Ord a, Num a) => HasBothInfinities (AffinelyExtendBoundedBoth a) where negInf = AffinelyExtendBoundedBoth unwrappedNegInf instance (Eq a, Bounded a) => HasPositiveInfinity (AffinelyExtendBoundedPos a) where posInf = AffinelyExtendBoundedPos unwrappedPosInfPos instance HasPositiveInfinity Float where posInf = 1 / 0 instance HasBothInfinities Float where negInf = (-1) / 0 instance HasPositiveInfinity Double where posInf = 1 / 0 instance HasBothInfinities Double where negInf = (-1) / 0 unpackSameBaseType :: (Eq a, HasBothInfinities a, BaseType a ~ a) => a -> AffinelyExtendBoth (BaseType a) unpackSameBaseType x = if | x == posInf -> PositiveInfinity | x == negInf -> NegativeInfinity | otherwise -> Finite x class CanAffinelyExtend a where type BaseType a affinelyExtend_c :: BaseType a -> a type UnpackType a type UnpackType a = AffinelyExtendBoth (BaseType a) unpack_c :: a -> UnpackType a default unpack_c :: (UnpackType a ~ AffinelyExtendBoth (BaseType a)) => a -> UnpackType a unpack_c = unpackBoth_c unpackBoth_c :: a -> AffinelyExtendBoth (BaseType a) default unpackBoth_c :: (Eq a, HasBothInfinities a, BaseType a ~ a) => a -> AffinelyExtendBoth (BaseType a) unpackBoth_c = unpackSameBaseType isPos :: a -> Bool isPos x = case (unpackBoth x) of PositiveInfinity -> True _ -> False isNegInf :: a -> Bool isNegInf x = case (unpackBoth x) of NegativeInfinity -> True _ -> False isInf :: a -> Bool isInf x = isPos x || isNegInf x isFinite :: a -> Bool isFinite = not . isInf instance CanAffinelyExtend (AffinelyExtendBoth a) where type BaseType (AffinelyExtendBoth a) = a affinelyExtend_c = Finite unpackBoth_c = id instance CanAffinelyExtend (AffinelyExtendPos a) where type BaseType (AffinelyExtendPos a) = a type UnpackType (AffinelyExtendPos a) = AffinelyExtendPos a unpack_c = unpackPos_c affinelyExtend_c = Finite unpackBoth_c = \case Finite x -> Finite x PositiveInfinity -> PositiveInfinity isPos = \case PositiveInfinity -> True _ -> False isNegInf _ = False isInf = isPos isFinite = not . isInf {-# INLINE [1] isPosBounded #-} isPosBounded :: (Ord a, Num a, Bounded a) => AffinelyExtendBoundedBoth a -> Bool isPosBounded = applyToBounded (== unwrappedPosInf) {-# INLINE [1] isNegInfBounded #-} isNegInfBounded :: (Ord a, Num a, Bounded a) => AffinelyExtendBoundedBoth a -> Bool isNegInfBounded = applyToBounded (== unwrappedNegInf) {-# INLINE [1] isInfBounded #-} isInfBounded :: (Ord a, Num a, Bounded a) => AffinelyExtendBoundedBoth a -> Bool isInfBounded = applyToBounded (\x -> abs x == unwrappedPosInf) {-# INLINE [1] isFiniteBounded #-} isFiniteBounded :: (Ord a, Num a, Bounded a) => AffinelyExtendBoundedBoth a -> Bool isFiniteBounded = applyToBounded (\x -> abs x /= unwrappedPosInf) {-# RULES "isPosBounded/pack" forall x. isPosBounded (packBoth x) = isPos x "isNegInfBounded/pack" forall x. isNegInfBounded (packBoth x) = isNegInf x "isInfBounded/pack" forall x. isInfBounded (packBoth x) = isInf x "isFiniteBounded/pack" forall x. isFiniteBounded (packBoth x) = isFinite x #-} instance (Ord a, Bounded a, Num a) => CanAffinelyExtend (AffinelyExtendBoundedBoth a) where type BaseType (AffinelyExtendBoundedBoth a) = a affinelyExtend_c = AffinelyExtendBoundedBoth unpackBoth_c (AffinelyExtendBoundedBoth x) = if | x == unwrappedPosInf -> PositiveInfinity | x == unwrappedNegInf -> NegativeInfinity | otherwise -> Finite x isPos = isPosBounded isNegInf = isNegInfBounded isInf = isInfBounded isFinite = isFiniteBounded {-# INLINE [1] isPosInfBoundedPos #-} isPosInfBoundedPos :: (Eq a, Bounded a) => AffinelyExtendBoundedPos a -> Bool isPosInfBoundedPos = applyToBounded (== unwrappedPosInfPos) {-# INLINE [1] isFiniteBoundedPos #-} isFiniteBoundedPos :: (Eq a, Bounded a) => AffinelyExtendBoundedPos a -> Bool isFiniteBoundedPos = applyToBounded (/= unwrappedPosInfPos) {-# RULES "isPosInfBoundedPos/pack" forall x. isPosInfBoundedPos (packPos x) = isPos x "isFiniteBoundedPos/pack" forall x. isFiniteBoundedPos (packPos x) = isFinite x #-} instance (Eq a, Bounded a) => CanAffinelyExtend (AffinelyExtendBoundedPos a) where type BaseType (AffinelyExtendBoundedPos a) = a type UnpackType (AffinelyExtendBoundedPos a) = AffinelyExtendPos a unpack_c = unpackPos_c affinelyExtend_c = AffinelyExtendBoundedPos unpackBoth_c (AffinelyExtendBoundedPos x) = if | x == unwrappedPosInfPos -> PositiveInfinity | otherwise -> Finite x isPos = isPosInfBoundedPos isNegInf _ = False isInf = isPos isFinite = isFiniteBoundedPos instance CanAffinelyExtendPos (AffinelyExtendPos a) where unpackPos_c = id instance (Eq a, Bounded a) => CanAffinelyExtendPos (AffinelyExtendBoundedPos a) where unpackPos_c (AffinelyExtendBoundedPos x) = if | x == unwrappedPosInfPos -> PositiveInfinity | otherwise -> Finite x instance CanAffinelyExtend Float where type BaseType Float = Float affinelyExtend_c = id unpackBoth_c = unpackSameBaseType instance CanAffinelyExtend Double where type BaseType Double = Double affinelyExtend_c = id unpackBoth_c = unpackSameBaseType -- Packing {-# INLINE [1] affinelyExtend #-} affinelyExtend :: CanAffinelyExtend a => BaseType a -> a affinelyExtend = affinelyExtend_c affinelyExtendBoth :: a -> AffinelyExtendBoth a affinelyExtendBoth = affinelyExtend affinelyExtendPos :: a -> AffinelyExtendPos a affinelyExtendPos = affinelyExtend affinelyExtendBoundedBoth :: (Ord a, Bounded a, Num a) => a -> AffinelyExtendBoundedBoth a affinelyExtendBoundedBoth = affinelyExtend affinelyExtendBoundedPos :: (Eq a, Bounded a) => a -> AffinelyExtendBoundedPos a affinelyExtendBoundedPos = affinelyExtend {-# INLINE unpack #-} unpack :: CanAffinelyExtend a => a -> UnpackType a unpack = unpack_c {-# INLINE [1] unpackBoth #-} unpackBoth :: CanAffinelyExtend a => a -> AffinelyExtendBoth (BaseType a) unpackBoth = unpackBoth_c class (CanAffinelyExtend a) => CanAffinelyExtendPos a where unpackPos_c :: a -> AffinelyExtendPos (BaseType a) {-# INLINE [1] unpackPos #-} unpackPos :: (CanAffinelyExtendPos a) => a -> AffinelyExtendPos (BaseType a) unpackPos = unpackPos_c {-# INLINE [1] packBoth #-} packBoth :: (HasBothInfinities a, CanAffinelyExtend a) => AffinelyExtendBoth (BaseType a) -> a packBoth = \case Finite x -> affinelyExtend x PositiveInfinity -> posInf NegativeInfinity -> negInf {-# INLINE [1] packPos #-} packPos :: (HasPositiveInfinity a, CanAffinelyExtend a) => AffinelyExtendPos (BaseType a)-> a packPos = \case Finite x -> affinelyExtend x PositiveInfinity -> posInf class CanAffinelyPack t where type CanAffinelyPackConstraint t a :: Constraint pack_c :: (CanAffinelyPackConstraint t a) => t (BaseType a) -> a instance CanAffinelyPack (AffinelyExtend True) where type CanAffinelyPackConstraint (AffinelyExtend True) a = (HasBothInfinities a, CanAffinelyExtend a) pack_c = packBoth instance CanAffinelyPack (AffinelyExtend False) where type CanAffinelyPackConstraint (AffinelyExtend False) a = (HasPositiveInfinity a, CanAffinelyExtend a) pack_c = packPos {-# INLINE pack #-} pack :: (CanAffinelyPack t, CanAffinelyPackConstraint t a) => t (BaseType a) -> a pack = pack_c {-# RULES "unpackBoth/packBoth" forall x. unpackBoth (packBoth x) = x "unpackPos/packPos" forall x. unpackPos (packPos x) = x #-} class GetRawVal a where getRawVal :: a -> BaseType a setRawVal :: BaseType a -> a instance GetRawVal (AffinelyExtendBoundedBoth a) where getRawVal (AffinelyExtendBoundedBoth x) = x setRawVal = AffinelyExtendBoundedBoth instance GetRawVal (AffinelyExtendBoundedPos a) where getRawVal (AffinelyExtendBoundedPos x) = x setRawVal = AffinelyExtendBoundedPos applyThroughBounded :: GetRawVal a => (BaseType a -> BaseType a) -> a -> a applyThroughBounded f = setRawVal . (applyToBounded f) applyToBounded :: GetRawVal a => (BaseType a -> b) -> a -> b applyToBounded f = f . getRawVal apply2ThroughBounded :: GetRawVal a => (BaseType a -> BaseType a -> BaseType a) -> a -> a -> a apply2ThroughBounded f x y = setRawVal (apply2ToBounded f x y) apply2ToBounded :: GetRawVal a => (BaseType a -> BaseType a -> b) -> a -> a -> b apply2ToBounded f x y = f (getRawVal x) (getRawVal y) applyAffine :: (UnpackType a ~ b, b ~ t (BaseType a), CanAffinelyExtend a, CanAffinelyPack t, CanAffinelyPackConstraint t a) => (b -> b) -> a -> a applyAffine f = pack . f . unpack applyAffine2 :: (UnpackType a ~ b, b ~ t (BaseType a), CanAffinelyExtend a, CanAffinelyPack t, CanAffinelyPackConstraint t a) => (b -> b -> b) -> a -> a -> a applyAffine2 f x y = pack (f (unpack x) (unpack y)) applyAffineOutPair2 :: (UnpackType a ~ b, b ~ t (BaseType a), CanAffinelyExtend a, CanAffinelyPack t, CanAffinelyPackConstraint t a) => (b -> b -> (b, b)) -> a -> a -> (a, a) applyAffineOutPair2 f x y = let (x', y') = f (unpack x) (unpack y) in (pack x', pack y') applyAffineNoPack :: (UnpackType a ~ b, b ~ t (BaseType a), CanAffinelyExtend a) => (b -> c) -> a -> c applyAffineNoPack f = f . unpack -- Eq instance Eq a => Eq (AffinelyExtendBoth a) where x == y = case (x,y) of (Finite x, Finite y) -> x == y (PositiveInfinity, PositiveInfinity) -> True (NegativeInfinity, NegativeInfinity) -> True _ -> False x /= y = case (x,y) of (Finite x, Finite y) -> x /= y (PositiveInfinity, PositiveInfinity) -> False (NegativeInfinity, NegativeInfinity) -> False _ -> True instance Eq a => Eq (AffinelyExtendPos a) where x == y = case (x,y) of (Finite x, Finite y) -> x == y (PositiveInfinity, PositiveInfinity) -> True _ -> False x /= y = case (x,y) of (Finite x, Finite y) -> x /= y (PositiveInfinity, PositiveInfinity) -> False _ -> True {-# INLINE [1] eqBounded #-} eqBounded :: (GetRawVal a, Eq (BaseType a)) => a -> a -> Bool eqBounded = apply2ToBounded (==) {-# RULES "eqBounded/pack" forall x y. (packPos x) `eqBounded` (packPos y) = x == y "eqBounded/pack" forall x y. (packBoth x) `eqBounded` (packBoth y) = x == y #-} {-# INLINE [1] neqBounded #-} neqBounded :: (GetRawVal a, Eq (BaseType a)) => a -> a -> Bool neqBounded = apply2ToBounded (/=) {-# RULES "neqBounded/pack" forall x y. (packPos x) `neqBounded` (packPos y) = x /= y "neqBounded/pack" forall x y. (packBoth x) `neqBounded` (packBoth y) = x /= y #-} instance Eq a => Eq (AffinelyExtendBoundedBoth a) where (==) = eqBounded (/=) = neqBounded instance Eq a => Eq (AffinelyExtendBoundedPos a) where (==) = eqBounded (/=) = neqBounded -- Ord instance Ord a => Ord (AffinelyExtendBoth a) where x `compare` y = case (x,y) of (Finite x, Finite y) -> x `compare` y (PositiveInfinity, PositiveInfinity) -> EQ (NegativeInfinity, NegativeInfinity) -> EQ (_, PositiveInfinity) -> LT (PositiveInfinity, _) -> GT (NegativeInfinity, _) -> LT (_, NegativeInfinity) -> GT x < y = case (x,y) of (Finite x, Finite y) -> x < y (PositiveInfinity, _) -> False (_, NegativeInfinity) -> False _ -> True x <= y = case (x,y) of (Finite x, Finite y) -> x <= y (_, PositiveInfinity) -> True (NegativeInfinity, _) -> True _ -> False x > y = case (x,y) of (Finite x, Finite y) -> x > y (_, PositiveInfinity) -> False (NegativeInfinity, _) -> False _ -> True x >= y = case (x,y) of (Finite x, Finite y) -> x >= y (PositiveInfinity, _) -> True (_, NegativeInfinity) -> True _ -> False min x y = case (x, y) of (Finite x, Finite y) -> Finite (min x y) (_, PositiveInfinity) -> x (PositiveInfinity, _) -> y _ -> NegativeInfinity max x y = case (x, y) of (Finite x, Finite y) -> Finite (max x y) (_, NegativeInfinity) -> x (NegativeInfinity, _) -> y _ -> PositiveInfinity instance Ord a => Ord (AffinelyExtendPos a) where x `compare` y = case (x,y) of (Finite x, Finite y) -> x `compare` y (PositiveInfinity, PositiveInfinity) -> EQ (Finite _, PositiveInfinity) -> LT (PositiveInfinity, Finite _) -> GT x < y = case (x,y) of (Finite x, Finite y) -> x < y (PositiveInfinity, _) -> False _ -> True x <= y = case (x,y) of (Finite x, Finite y) -> x <= y (_, PositiveInfinity) -> True _ -> False x > y = case (x,y) of (Finite x, Finite y) -> x > y (_, PositiveInfinity) -> False _ -> True x >= y = case (x,y) of (Finite x, Finite y) -> x >= y (PositiveInfinity, _) -> True _ -> False min x y = case (x, y) of (Finite x, Finite y) -> Finite (min x y) (_, PositiveInfinity) -> x (PositiveInfinity, _) -> y max x y = case (x, y) of (Finite x, Finite y) -> Finite (max x y) _ -> PositiveInfinity {-# INLINE [1] compareBounded #-} compareBounded :: (GetRawVal a, Ord (BaseType a)) => a -> a -> Ordering compareBounded = apply2ToBounded compare {-# RULES "compareBounded/pack" forall x y. (packPos x) `compareBounded` (packPos y) = x `compare` y "compareBounded/pack" forall x y. (packBoth x) `compareBounded` (packBoth y) = x `compare` y #-} {-# INLINE [1] ltBounded #-} ltBounded :: (GetRawVal a, Ord (BaseType a)) => a -> a -> Bool ltBounded = apply2ToBounded (<) {-# RULES "ltBounded/pack" forall x y. (packPos x) `ltBounded` (packPos y) = x < y "ltBounded/pack" forall x y. (packBoth x) `ltBounded` (packBoth y) = x < y #-} {-# INLINE [1] gtBounded #-} gtBounded :: (GetRawVal a, Ord (BaseType a)) => a -> a -> Bool gtBounded = apply2ToBounded (>) {-# RULES "gtBounded/pack" forall x y. (packPos x) `gtBounded` (packPos y) = x > y "gtBounded/pack" forall x y. (packBoth x) `gtBounded` (packBoth y) = x > y #-} {-# INLINE [1] lteBounded #-} lteBounded :: (GetRawVal a, Ord (BaseType a)) => a -> a -> Bool lteBounded = apply2ToBounded (<=) {-# RULES "lteBounded/pack" forall x y. (packPos x) `lteBounded` (packPos y) = x <= y "lteBounded/pack" forall x y. (packBoth x) `lteBounded` (packBoth y) = x <= y #-} {-# INLINE [1] gteBounded #-} gteBounded :: (GetRawVal a, Ord (BaseType a)) => a -> a -> Bool gteBounded = apply2ToBounded (>=) {-# RULES "gteBounded/pack" forall x y. (packPos x) `gteBounded` (packPos y) = x >= y "gteBounded/pack" forall x y. (packBoth x) `gteBounded` (packBoth y) = x >= y #-} {-# INLINE [1] maxBounded #-} maxBounded :: (GetRawVal a, Ord (BaseType a)) => a -> a -> a maxBounded = apply2ThroughBounded max {-# RULES "maxBounded/pack" forall x y. maxBounded (packPos x) (packPos y) = max x y "maxBounded/pack" forall x y. maxBounded (packBoth x) (packBoth y) = max x y #-} {-# INLINE [1] minBounded #-} minBounded :: (GetRawVal a, Ord (BaseType a)) => a -> a -> a minBounded = apply2ThroughBounded min {-# RULES "minBounded/pack" forall x y. minBounded (packPos x) (packPos y) = min x y "minBounded/pack" forall x y. minBounded (packBoth x) (packBoth y) = min x y #-} instance Ord a => Ord (AffinelyExtendBoundedBoth a) where compare = compareBounded (<) = ltBounded (>) = gtBounded (<=) = lteBounded (>=) = gteBounded min = minBounded max = maxBounded instance Ord a => Ord (AffinelyExtendBoundedPos a) where compare = compareBounded (<) = ltBounded (>) = gtBounded (<=) = lteBounded (>=) = gteBounded min = minBounded max = maxBounded -- Show showsPosInf :: ShowS showsPosInf = shows (posInf :: Double) showsNegInf :: ShowS showsNegInf = shows (negInf :: Double) strPosInf = showsPosInf "" strNegInf = showsNegInf "" instance Show a => Show (AffinelyExtendBoth a) where showsPrec _ = \case (Finite x) -> shows x PositiveInfinity -> showsPosInf NegativeInfinity -> showsNegInf instance Show a => Show (AffinelyExtendPos a) where showsPrec _ = \case (Finite x) -> shows x PositiveInfinity -> showsPosInf instance (Ord a, Bounded a, Num a, Show a) => Show (AffinelyExtendBoundedBoth a) where showsPrec _ x = if | isPos x -> showsPosInf | isNegInf x -> showsNegInf | otherwise -> shows x instance (Eq a, Bounded a, Show a) => Show (AffinelyExtendBoundedPos a) where showsPrec _ x = if | isFinite x -> shows x | otherwise -> showsPosInf -- Read readsPrecInfGeneric :: forall a. (CanAffinelyExtend a, Read (BaseType a)) => (ReadS a) -> Int -> ReadS a readsPrecInfGeneric infParse n s = let ordinaryParse :: [(BaseType a, String)] ordinaryParse = readsPrec n s in case ordinaryParse of (_:_) -> map (\(x,y) -> (affinelyExtend x, y)) ordinaryParse _ -> infParse s maybeTake :: Eq a => [a] -> [a] -> Maybe [a] maybeTake findStr str = let (toCheck, rest) = splitAt (length findStr) str in if (toCheck == findStr) then Just rest else Nothing maybeTakeVal :: Eq a => b -> [a] -> [a] -> Maybe (b, [a]) maybeTakeVal v findStr str = do r <- maybeTake findStr str return (v, r) maybeParseShow :: Show a => a -> String -> Maybe (a, String) maybeParseShow v str = maybeTakeVal v (show v) str maybeParsePosInf :: (HasPositiveInfinity a, Show a) => String -> Maybe (a, String) maybeParsePosInf = maybeParseShow posInf maybeParseNegInf :: (HasBothInfinities a, Show a) => String -> Maybe (a, String) maybeParseNegInf = maybeParseShow negInf parseBothInf :: (CanAffinelyExtend a, HasBothInfinities a, Show a) => ReadS a parseBothInf s = maybeToList (maybeParsePosInf s <|> maybeParseNegInf s) parsePosInf :: (CanAffinelyExtend a, HasPositiveInfinity a, Show a) => ReadS a parsePosInf = maybeToList . maybeParsePosInf readBothInf :: (Read (BaseType a), CanAffinelyExtend a, HasBothInfinities a, Show a) => Int -> ReadS a readBothInf = readsPrecInfGeneric parseBothInf readPosInf :: (Read (BaseType a), CanAffinelyExtend a, HasPositiveInfinity a, Show a) => Int -> ReadS a readPosInf = readsPrecInfGeneric parsePosInf instance (Show a, Read a) => Read (AffinelyExtendBoth a) where readsPrec = readBothInf instance (Show a, Read a) => Read (AffinelyExtendPos a) where readsPrec = readPosInf instance (Bounded a, Ord a, Num a, Read a, Show a) => Read (AffinelyExtendBoundedBoth a) where readsPrec = readBothInf instance (Bounded a, Eq a, Read a, Show a) => Read (AffinelyExtendBoundedPos a) where readsPrec = readPosInf -- Enum toEnum' :: (CanAffinelyExtend a, Enum (BaseType a)) => Int -> a toEnum' x = affinelyExtend (toEnum x) fromEnum' :: (CanAffinelyExtend a, Enum (BaseType a)) => a -> Int fromEnum' x = case (unpackBoth x) of Finite x -> fromEnum x _ -> error "Can't 'fromEnum' an infinity" succ' :: (CanAffinelyExtend a, Enum (BaseType a)) => a -> a succ' x = case unpackBoth x of Finite x -> affinelyExtend (succ x) _ -> x pred' :: (CanAffinelyExtend a, Enum (BaseType a)) => a -> a pred' x = case unpackBoth x of Finite x -> affinelyExtend (pred x) _ -> x enumFrom' :: (CanAffinelyExtend a, Enum (BaseType a)) => a -> [a] enumFrom' x = case unpackBoth x of Finite x -> map affinelyExtend (enumFrom x) _ -> repeat x enumFromThen' :: (CanAffinelyExtend a, Enum (BaseType a)) => a -> a -> [a] enumFromThen' x y = case (unpackBoth x, unpackBoth y) of (Finite x, Finite y) -> map affinelyExtend (enumFromThen x y) _ -> error "Can't enumFromThen an infinity." enumFromTo' :: (CanAffinelyExtend a, Enum (BaseType a)) => a -> a -> [a] enumFromTo' x y = case (unpackBoth x, unpackBoth y) of (Finite x, Finite y) -> map affinelyExtend (enumFromTo x y) (Finite x, PositiveInfinity) -> map affinelyExtend (enumFrom x) (Finite _, NegativeInfinity) -> [] (NegativeInfinity, Finite _) -> repeat x (NegativeInfinity, PositiveInfinity) -> repeat x (PositiveInfinity, NegativeInfinity) -> [] (PositiveInfinity, Finite _) -> [] _ -> error "Can't enumFromTo identical infinities." enumFromThenTo' :: (CanAffinelyExtend a, Enum (BaseType a), Ord (BaseType a)) => a -> a -> a -> [a] enumFromThenTo' x y z = case (unpackBoth x, unpackBoth y, unpackBoth z) of (Finite x, Finite y, Finite z) -> map affinelyExtend (enumFromThenTo x y z) (Finite x, Finite y, PositiveInfinity) -> if (x <= y) then map affinelyExtend (enumFromThen x y) else [] (Finite x, Finite y, NegativeInfinity) -> if (x >= y) then map affinelyExtend (enumFromThen x y) else [] _ -> error "Can't enumFromThen infinity." instance (Ord a, Enum a) => Enum (AffinelyExtendBoth a) where toEnum = toEnum' fromEnum = fromEnum' succ = succ' pred = pred' enumFrom = enumFrom' enumFromThen = enumFromThen' enumFromThenTo = enumFromThenTo' instance (Ord a, Enum a) => Enum (AffinelyExtendPos a) where toEnum = toEnum' fromEnum = fromEnum' succ = succ' pred = pred' enumFrom = enumFrom' enumFromThen = enumFromThen' enumFromThenTo = enumFromThenTo' instance (Bounded a, Ord a, Enum a, Num a) => Enum (AffinelyExtendBoundedBoth a) where toEnum = toEnum' fromEnum = fromEnum' succ = succ' pred = pred' enumFrom = enumFrom' enumFromThen = enumFromThen' enumFromThenTo = enumFromThenTo' instance (Bounded a, Ord a, Enum a, Num a) => Enum (AffinelyExtendBoundedPos a) where toEnum = toEnum' fromEnum = fromEnum' succ = succ' pred = pred' enumFrom = enumFrom' enumFromThen = enumFromThen' enumFromThenTo = enumFromThenTo' -- Num signToInf :: (Ord a, Num a, Num b, HasBothInfinities b) => a -> b signToInf x = case (x `compare` 0) of GT -> posInf LT -> negInf EQ -> 0 signToNegInf :: (Ord a, Num a, Num b, HasBothInfinities b) => a -> b signToNegInf x = case (x `compare` 0) of GT -> negInf LT -> posInf EQ -> 0 signToInfPos :: (Ord a, Num a, Num b, HasPositiveInfinity b) => a -> b signToInfPos x = case (x `compare` 0) of GT -> posInf EQ -> 0 LT -> error "Operation produced negative infinity for type with only positive infinity." signToInfDivide :: (Ord a, Num a, Num b, HasBothInfinities b) => a -> b signToInfDivide x = case (x `compare` 0) of GT -> posInf LT -> negInf EQ -> error "Can't divide by 0" signToNegInfDivide :: (Ord a, Num a, Num b, HasBothInfinities b) => a -> b signToNegInfDivide x = case (x `compare` 0) of GT -> negInf LT -> posInf EQ -> error "Can't divide by 0" signToInfDividePos :: (Ord a, Num a, Num b, HasPositiveInfinity b) => a -> b signToInfDividePos x = case (x `compare` 0) of GT -> posInf LT -> error "Operation produced negative infinity for type with only positive infinity." EQ -> error "Can't divide by 0" instance (Ord a, Num a) => Num (AffinelyExtendBoth a) where x + y = case (x,y) of (Finite x, Finite y) -> Finite (x + y) (_, Finite _) -> x (Finite _, _) -> y (PositiveInfinity, PositiveInfinity) -> PositiveInfinity (NegativeInfinity, NegativeInfinity) -> NegativeInfinity _ -> error "Can't add positive and negative infinity" x - y = case (x,y) of (Finite x, Finite y) -> Finite (x - y) (_, Finite _) -> x (Finite _, _) -> negate y (PositiveInfinity, NegativeInfinity) -> PositiveInfinity (NegativeInfinity, PositiveInfinity) -> NegativeInfinity _ -> error "Can't subtract identical infinities" x * y = case (x,y) of (Finite x, Finite y) -> Finite (x * y) (Finite x, PositiveInfinity) -> signToInf x (PositiveInfinity, Finite y) -> signToInf y (Finite x, NegativeInfinity) -> signToNegInf x (NegativeInfinity, Finite y) -> signToNegInf y (PositiveInfinity, PositiveInfinity) -> PositiveInfinity (PositiveInfinity, NegativeInfinity) -> NegativeInfinity (NegativeInfinity, PositiveInfinity) -> NegativeInfinity (NegativeInfinity, NegativeInfinity) -> PositiveInfinity signum = \case Finite x -> Finite (signum x) PositiveInfinity -> 1 NegativeInfinity -> -1 fromInteger = Finite . fromInteger negate = \case Finite x -> Finite (negate x) PositiveInfinity -> NegativeInfinity NegativeInfinity -> PositiveInfinity abs = \case Finite x -> Finite (abs x) _ -> PositiveInfinity instance (Ord a, Num a) => Num (AffinelyExtendPos a) where x + y = case (x,y) of (Finite x, Finite y) -> Finite (x + y) _ -> PositiveInfinity x - y = case (x,y) of (Finite x, Finite y) -> Finite (x - y) (_, Finite _) -> PositiveInfinity (_, PositiveInfinity) -> error "Can't subtract positive infinity from type with no negative infinity" x * y = case (x,y) of (Finite x, Finite y) -> Finite (x * y) (Finite x, PositiveInfinity) -> signToInfPos x (PositiveInfinity, Finite y) -> signToInfPos y (PositiveInfinity, PositiveInfinity) -> PositiveInfinity signum = \case Finite x -> Finite (signum x) PositiveInfinity -> 1 fromInteger = Finite . fromInteger negate x = case x of Finite x -> Finite (negate x) PositiveInfinity -> error "Can't negate positive infinity with type with no negative infinity" abs = \case Finite x -> Finite (abs x) PositiveInfinity -> PositiveInfinity {-# INLINE [1] fromIntegerGeneric #-} fromIntegerGeneric :: (Ord (BaseType a), Num (BaseType a), CanAffinelyExtend a) => Integer -> a fromIntegerGeneric = affinelyExtend . fromInteger {-# INLINE [1] negateBounded #-} negateBounded :: (Ord (BaseType a), Num (BaseType a), CanAffinelyExtend a, GetRawVal a) => a -> a negateBounded = applyThroughBounded negate {-# INLINE [1] signumBounded #-} signumBounded :: (Ord (BaseType a), Num (BaseType a), CanAffinelyExtend a, GetRawVal a) => a -> a signumBounded = applyThroughBounded signum {-# INLINE [1] absBounded #-} absBounded :: (Ord (BaseType a), Num (BaseType a), CanAffinelyExtend a, GetRawVal a) => a -> a absBounded = applyThroughBounded abs instance (Ord a, Num a, Bounded a) => Num (AffinelyExtendBoundedBoth a) where (+) = applyAffine2 (+) (*) = applyAffine2 (*) (-) = applyAffine2 (-) negate = negateBounded signum = signumBounded fromInteger = fromIntegerGeneric abs = absBounded instance (Ord a, Num a, Bounded a) => Num (AffinelyExtendBoundedPos a) where (+) = applyAffine2 (+) (*) = applyAffine2 (*) (-) = applyAffine2 (-) negate = negateBounded signum = signumBounded fromInteger = fromIntegerGeneric abs = absBounded {-# RULES "negate/packBoth" forall x. negateBounded (packBoth x) = packBoth (negate x) "negate/packBoth" forall x. negateBounded (packPos x) = packPos (negate x) "signum/packBoth" forall x. signumBounded (packBoth x) = packBoth (signum x) "signum/packBoth" forall x. signumBounded (packPos x) = packPos (signum x) "abs/packBoth" forall x. absBounded (packBoth x) = packBoth (abs x) "abs/packBoth" forall x. absBounded (packPos x) = packPos (abs x) "unpackBoth/fromInteger" forall x. unpackBoth (fromIntegerGeneric x) = fromInteger x "unpackBoth/fromInteger" forall x. unpackPos (fromIntegerGeneric x) = fromInteger x #-} -- Real instance (Real a) => Real (AffinelyExtendBoth a) where toRational x = case x of Finite x -> toRational x _ -> error "Can't toRational an infinite number" instance (Real a) => Real (AffinelyExtendPos a) where toRational x = case x of Finite x -> toRational x _ -> error "Can't toRational an infinite number" instance (Real a, Bounded a) => Real (AffinelyExtendBoundedBoth a) where toRational = applyAffineNoPack toRational instance (Real a, Bounded a) => Real (AffinelyExtendBoundedPos a) where toRational = applyAffineNoPack toRational -- Fractional instance (Ord a, Fractional a) => Fractional (AffinelyExtendBoth a) where x / y = case (x,y) of (Finite x, Finite y) -> Finite (x / y) (Finite _, _) -> 0 (PositiveInfinity, Finite y) -> signToInfDivide y (NegativeInfinity, Finite y) -> signToNegInfDivide y _ -> error "Can't divide infinities" recip = \case (Finite x) -> (Finite (recip x)) _ -> 0 fromRational = affinelyExtend . fromRational instance (Ord a, Fractional a) => Fractional (AffinelyExtendPos a) where x / y = case (x,y) of (Finite x, Finite y) -> Finite (x / y) (Finite _, PositiveInfinity) -> 0 (PositiveInfinity, Finite y) -> signToInfDividePos y (PositiveInfinity, PositiveInfinity) -> error "Can't divide infinities" recip = \case (Finite x) -> (Finite (recip x)) _ -> 0 fromRational = affinelyExtend . fromRational instance (Ord a, Bounded a, Fractional a) => Fractional (AffinelyExtendBoundedBoth a) where (/) = applyAffine2 (/) recip = applyAffine recip fromRational = fromRationalGeneric instance (Ord a, Bounded a, Fractional a) => Fractional (AffinelyExtendBoundedPos a) where (/) = applyAffine2 (/) recip = applyAffine recip fromRational = fromRationalGeneric {-# INLINE [1] fromRationalGeneric #-} fromRationalGeneric :: (Ord (BaseType a), Num (BaseType a), Fractional (BaseType a), CanAffinelyExtend a) => Rational -> a fromRationalGeneric = affinelyExtend . fromRational {-# RULES "unpackBoth/fromRational" forall x. unpackBoth (fromRationalGeneric x) = fromRational x #-} instance Integral a => Integral (AffinelyExtendBoth a) where quot x y = case (x,y) of (Finite x, Finite y) -> Finite (x `quot` y) (Finite _, _) -> 0 (PositiveInfinity, Finite y) -> signToInfDivide y (NegativeInfinity, Finite y) -> signToNegInfDivide y _ -> error "Can't 'quot' two infinities" rem x y = case (x,y) of (Finite x, Finite y) -> Finite (x `rem` y) (Finite _, _) -> x _ -> error "Can't have infinity as first argument of 'rem'" div x y = case (x,y) of (Finite x, Finite y) -> Finite (x `div` y) (Finite _, _) -> 0 (PositiveInfinity, Finite y) -> signToInfDivide y (NegativeInfinity, Finite y) -> signToNegInfDivide y _ -> error "Can't 'div' two infinities" mod x y = case (x,y) of (Finite x, Finite y) -> Finite (x `mod` y) (Finite x', PositiveInfinity) -> if (x' >= 0) then x else error "Can't 'mod' with mixed signs and one infinity." (Finite x', NegativeInfinity) -> if (x' <= 0) then x else error "Can't 'mod' with mixed signs and one infinity." _ -> error "Can't have infinity as first argument of 'mod'" quotRem x y = case (x,y) of (Finite x, Finite y) -> let (x', y') = (x `quotRem` y) in (Finite x', Finite y') (Finite _, _) -> (0, x) (PositiveInfinity, Finite y) -> (signToInfDivide y, error "Can't have infinity as first argument of 'rem'") (NegativeInfinity, Finite y) -> (signToNegInfDivide y, error "Can't have infinity as first argument of 'rem'") _ -> error "Can't 'quotRem' two infinities" divMod x y = case (x,y) of (Finite x, Finite y) -> let (x', y') = (x `divMod` y) in (Finite x', Finite y') (Finite x', PositiveInfinity) -> (0, if (x' >= 0) then x else error "Can't 'mod' with mixed signs and one infinity.") (Finite x', NegativeInfinity) -> (0, if (x' <= 0) then x else error "Can't 'mod' with mixed signs and one infinity.") (PositiveInfinity, Finite y) -> (signToInfDivide y, error "Can't have infinity as first argument of 'mod'") (NegativeInfinity, Finite y) -> (signToNegInfDivide y, error "Can't have infinity as first argument of 'mod'") _ -> error "Can't 'divMod' two infinities" toInteger = \case (Finite x) -> toInteger x _ -> error "Can't 'toInteger' infinity" instance Integral a => Integral (AffinelyExtendPos a) where quot x y = case (x,y) of (Finite x, Finite y) -> Finite (x `quot` y) (Finite _, PositiveInfinity) -> 0 (PositiveInfinity, Finite y) -> signToInfDividePos y (PositiveInfinity, PositiveInfinity) -> error "Can't 'quot' two infinities" rem x y = case (x,y) of (Finite x, Finite y) -> Finite (x `rem` y) (Finite _, PositiveInfinity) -> x (PositiveInfinity, _) -> error "Can't have infinity as first argument of 'rem'" div x y = case (x,y) of (Finite x, Finite y) -> Finite (x `div` y) (Finite _, PositiveInfinity) -> 0 (PositiveInfinity, Finite y) -> signToInfDividePos y (PositiveInfinity, PositiveInfinity) -> error "Can't 'div' two infinities" mod x y = case (x,y) of (Finite x, Finite y) -> Finite (x `mod` y) (Finite _, PositiveInfinity) -> x (PositiveInfinity, _) -> error "Can't have infinity as first argument of 'mod'" quotRem x y = case (x,y) of (Finite x, Finite y) -> let (x', y') = (x `quotRem` y) in (Finite x', Finite y') (Finite _, PositiveInfinity) -> (0, x) (PositiveInfinity, Finite y) -> (signToInfDividePos y, error "Can't have infinity as first argument of 'rem'") (PositiveInfinity, PositiveInfinity) -> error "Can't 'quotRem' two infinities" divMod x y = case (x,y) of (Finite x, Finite y) -> let (x', y') = (x `divMod` y) in (Finite x', Finite y') (Finite x', PositiveInfinity) -> (0, if (x' >= 0) then x else error "Can't 'mod' with mixed signs and one infinity.") (PositiveInfinity, Finite y) -> (signToInfDividePos y, error "Can't have infinity as first argument of 'mod'") (PositiveInfinity, PositiveInfinity) -> error "Can't 'divMod' two infinities" toInteger = \case (Finite x) -> toInteger x PositiveInfinity -> error "Can't 'toInteger' infinity" {-# INLINE [1] remBounded #-} remBounded :: (GetRawVal a, CanAffinelyExtend a, Integral (BaseType a)) => a -> a -> a remBounded x y = assert (isFinite x) (apply2ThroughBounded rem x y) {-# INLINE [1] modBounded #-} modBounded :: (GetRawVal a, CanAffinelyExtend a, Integral (BaseType a)) => a -> a -> a modBounded x y = assert (isFinite x) (apply2ThroughBounded mod x y) {-# INLINE [1] toIntegerBounded #-} toIntegerBounded :: (GetRawVal a, CanAffinelyExtend a, Integral (BaseType a)) => a -> Integer toIntegerBounded x = assert (isFinite x) (toInteger (getRawVal x)) instance (Bounded a, Integral a) => Integral (AffinelyExtendBoundedBoth a) where quot = applyAffine2 quot rem = remBounded div = applyAffine2 div mod = modBounded quotRem = applyAffineOutPair2 quotRem divMod = applyAffineOutPair2 divMod toInteger = toIntegerBounded instance (Bounded a, Integral a) => Integral (AffinelyExtendBoundedPos a) where quot = applyAffine2 quot rem = remBounded div = applyAffine2 div mod = modBounded quotRem = applyAffineOutPair2 quotRem divMod = applyAffineOutPair2 divMod toInteger = toIntegerBounded {-# RULES "rem/packBoth" forall x y. remBounded (packBoth x) (packBoth y) = packBoth (rem x y) "rem/packPos" forall x y. remBounded (packPos x) (packPos y) = packPos (rem x y) "mod/packBoth" forall x y. modBounded (packBoth x) (packBoth y) = packBoth (mod x y) "mod/packPos" forall x y. modBounded (packPos x) (packPos y) = packPos (mod x y) "toInteger/packBoth" forall x. toIntegerBounded (packBoth x) = toInteger x "toInteger/packPos" forall x. toIntegerBounded (packPos x) = toInteger x #-}