Safe Haskell | None |
---|---|
Language | Haskell2010 |
This package has four ways to extend any numerical type to add infinities:
- Both infinities with GADT:
AffinelyExtendBoth
, creation:affinelyExtendBoth
- Positive infinity only with GADT:
AffinelyExtendPos
, creation:affinelyExtendPos
- Both infinities with upper/lower bounds as infinity:
AffinelyExtendBoundedBoth
, creation:affinelyExtendBoundedBoth
- 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
- 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. - 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.
Documentation
data AffinelyExtend hasNegativeInfinity a where Source #
NegativeInfinity :: AffinelyExtend True a | |
Finite :: a -> AffinelyExtend h a | |
PositiveInfinity :: AffinelyExtend h a |
affinelyExtend :: CanAffinelyExtend a => BaseType a -> a Source #
type AffinelyExtendBoth a = AffinelyExtend True a Source #
affinelyExtendBoth :: a -> AffinelyExtendBoth a Source #
type AffinelyExtendPos a = AffinelyExtend False a Source #
affinelyExtendPos :: a -> AffinelyExtendPos a Source #
data AffinelyExtendBoundedBoth a Source #
affinelyExtendBoundedBoth :: (Ord a, Bounded a, Num a) => a -> AffinelyExtendBoundedBoth a Source #
data AffinelyExtendBoundedPos a Source #
(Bounded a, Ord a, Enum a, Num a) => Enum (AffinelyExtendBoundedPos a) Source # | |
Eq a => Eq (AffinelyExtendBoundedPos a) Source # | |
(Ord a, Bounded a, Fractional a) => Fractional (AffinelyExtendBoundedPos a) Source # | |
(Bounded a, Integral a) => Integral (AffinelyExtendBoundedPos a) Source # | |
(Ord a, Num a, Bounded a) => Num (AffinelyExtendBoundedPos a) Source # | |
Ord a => Ord (AffinelyExtendBoundedPos a) Source # | |
(Bounded a, Eq a, Read a, Show a) => Read (AffinelyExtendBoundedPos a) Source # | |
(Real a, Bounded a) => Real (AffinelyExtendBoundedPos a) Source # | |
(Eq a, Bounded a, Show a) => Show (AffinelyExtendBoundedPos a) Source # | |
(Eq a, Bounded a) => CanAffinelyExtendPos (AffinelyExtendBoundedPos a) Source # | |
(Eq a, Bounded a) => CanAffinelyExtend (AffinelyExtendBoundedPos a) Source # | |
(Eq a, Bounded a) => HasPositiveInfinity (AffinelyExtendBoundedPos a) Source # | |
type BaseType (AffinelyExtendBoundedPos a) Source # | |
type UnpackType (AffinelyExtendBoundedPos a) Source # | |
affinelyExtendBoundedPos :: (Eq a, Bounded a) => a -> AffinelyExtendBoundedPos a Source #
class CanAffinelyExtend a where Source #
affinelyExtend_c :: BaseType a -> a Source #
unpack_c :: a -> UnpackType a Source #
unpack_c :: UnpackType a ~ AffinelyExtendBoth (BaseType a) => a -> UnpackType a Source #
unpackBoth_c :: a -> AffinelyExtendBoth (BaseType a) Source #
unpackBoth_c :: (Eq a, HasBothInfinities a, BaseType a ~ a) => a -> AffinelyExtendBoth (BaseType a) Source #
CanAffinelyExtend Double Source # | |
CanAffinelyExtend Float Source # | |
(Eq a, Bounded a) => CanAffinelyExtend (AffinelyExtendBoundedPos a) Source # | |
(Ord a, Bounded a, Num a) => CanAffinelyExtend (AffinelyExtendBoundedBoth a) Source # | |
CanAffinelyExtend (AffinelyExtendPos a) Source # | |
CanAffinelyExtend (AffinelyExtendBoth a) Source # | |
isPos :: CanAffinelyExtend a => a -> Bool Source #
isNegInf :: CanAffinelyExtend a => a -> Bool Source #
isInf :: CanAffinelyExtend a => a -> Bool Source #
isFinite :: CanAffinelyExtend a => a -> Bool Source #
affinelyExtend_c :: CanAffinelyExtend a => BaseType a -> a Source #
unpack_c :: CanAffinelyExtend a => a -> UnpackType a Source #
unpackBoth_c :: CanAffinelyExtend a => a -> AffinelyExtendBoth (BaseType a) Source #
class CanAffinelyExtend a => CanAffinelyExtendPos a where Source #
unpackPos_c :: a -> AffinelyExtendPos (BaseType a) Source #
(Eq a, Bounded a) => CanAffinelyExtendPos (AffinelyExtendBoundedPos a) Source # | |
CanAffinelyExtendPos (AffinelyExtendPos a) Source # | |
unpackPos_c :: CanAffinelyExtendPos a => a -> AffinelyExtendPos (BaseType a) Source #
class HasPositiveInfinity a where Source #
posInf :: HasPositiveInfinity a => a Source #
class HasPositiveInfinity a => HasBothInfinities a where Source #
negInf :: HasBothInfinities a => a Source #