Copyright | © 2014 Herbert Valerio Riedel |
---|---|
License | BSD-style (see the LICENSE file) |
Maintainer | Herbert Valerio Riedel <hvr@gnu.org> |
Stability | experimental |
Portability | GHC ≥ 7.8 |
Safe Haskell | None |
Language | Haskell2010 |
This module provides for statically or dynamically checked
conversions between Integral
types.
- intCast :: (Integral a, Integral b, IsIntSubType a b ~ True) => a -> b
- intCastIso :: (Integral a, Integral b, IsIntTypeIso a b ~ True) => a -> b
- intCastEq :: (Integral a, Integral b, IsIntTypeEq a b ~ True) => a -> b
- intCastMaybe :: (Integral a, Integral b, Bits a, Bits b) => a -> Maybe b
- type family IntBaseType a :: IntBaseTypeK
- data IntBaseTypeK
- type IsIntSubType a b = IsIntBaseSubType (IntBaseType a) (IntBaseType b)
- type family IsIntBaseSubType a b :: Bool
- type IsIntTypeIso a b = IsIntBaseTypeIso (IntBaseType a) (IntBaseType b)
- type family IsIntBaseTypeIso a b :: Bool
- type IsIntTypeEq a b = IsIntBaseTypeEq (IntBaseType a) (IntBaseType b)
- type family IsIntBaseTypeEq a b :: Bool
Conversion functions
statically checked
intCast :: (Integral a, Integral b, IsIntSubType a b ~ True) => a -> b Source
Statically checked integer conversion which satisfies the property
Note: This is just a type-restricted alias of fromIntegral
and
should therefore lead to the same compiled code as if
fromIntegral
had been used instead of intCast
.
intCastIso :: (Integral a, Integral b, IsIntTypeIso a b ~ True) => a -> b Source
Statically checked integer conversion which satisfies the properties
∀β .
intCastIso
(intCastIso
a ∷ β) == atoInteger
(intCastIso
a) ==toInteger
b (iftoInteger
a ==toInteger
b)
Note: This is just a type-restricted alias of fromIntegral
and
should therefore lead to the same compiled code as if
fromIntegral
had been used instead of intCast
.
intCastEq :: (Integral a, Integral b, IsIntTypeEq a b ~ True) => a -> b Source
Version of intCast
restricted to casts between types with same value domain.
dynamically checked
intCastMaybe :: (Integral a, Integral b, Bits a, Bits b) => a -> Maybe b Source
Run-time-checked integer conversion
This is an optimized version of the following generic code below
intCastMaybeRef :: (Integral a, Integral b) => a -> Maybe b intCastMaybeRef x | toInteger x == toInteger y = Just y | otherwise = Nothing where y = fromIntegral x
The code above is rather inefficient as it needs to go via the
Integer
type. The function intCastMaybe
, however, is marked INLINEABLE
and
if both integral types are statically known, GHC will be able
optimize the code signficantly (for -O1
and better).
For instance (as of GHC 7.8.1) the following definitions
w16_to_i32 = intCastMaybe :: Word16 -> Maybe Int32 i16_to_w16 = intCastMaybe :: Int16 -> Maybe Word16
are translated into the following (simplified) GHC Core language
w16_to_i32 = \x -> Just (case x of _ { W16# x# -> I32# (word2Int# x#) }) i16_to_w16 = \x -> case eta of _ { I16# b1 -> case tagToEnum# (<=# 0 b1) of _ { False -> Nothing ; True -> Just (W16# (narrow16Word# (int2Word# b1))) } }
Registering new integer types
- For
intCastMaybe
you need to provide type-class instances ofBits
(andIntegral
). - For
intCast
,intCastIso
, andintCastEq
simply declare instances for theIntBaseType
type-family (as well as type-class instances ofIntegral
) as described below.
type family IntBaseType a :: IntBaseTypeK Source
The (open) type family IntBaseType
encodes type-level
information about the value range of an integral type.
This module also provides type family instances for the standard Haskell 2010 integral types (including Foreign.C.Types).
Here's a simple example for registering a custom type with the Data.IntCast facilities:
-- user-implemented unsigned 4-bit integer data Nibble = … -- declare meta-information type instanceIntBaseType
MyWord7 =FixedIntTag
4 -- user-implemented signed 7-bit integer data MyInt7 = … -- declare meta-information type instanceIntBaseType
MyWord7 =FixedIntTag
7
The type-level predicate IsIntSubType
provides a partial
ordering based on the types above. See also intCast
.
data IntBaseTypeK Source
(Kind) Meta-information about integral types.
If also a Bits
instance is defined, the type-level information
provided by IntBaseType
ought to match the meta-information that
is conveyed by the Bits
class' isSigned
and bitSizeMaybe
methods.
FixedIntTag Nat | fixed-width n-bit integers with value range [-2ⁿ⁻¹, 2ⁿ⁻¹-1]. |
FixedWordTag Nat | fixed-width n-bit integers with value range [0, 2ⁿ-1]. |
BigIntTag | integers with value range ]-∞,+∞[. |
BigWordTag | naturals with value range [0,+∞[. |
type (==) IntBaseTypeK a b = IsIntBaseTypeEq a b |
Type-level predicates
The following type-level predicates are used by intCast
,
intCastIso
, and intCastEq
respectively.
type IsIntSubType a b = IsIntBaseSubType (IntBaseType a) (IntBaseType b) Source
type family IsIntBaseSubType a b :: Bool Source
IsIntBaseSubType a a = True | |
IsIntBaseSubType a BigIntTag = True | |
IsIntBaseSubType (FixedWordTag a) BigWordTag = True | |
IsIntBaseSubType (FixedIntTag a) (FixedIntTag b) = a <=? b | |
IsIntBaseSubType (FixedWordTag a) (FixedWordTag b) = a <=? b | |
IsIntBaseSubType (FixedWordTag a) (FixedIntTag b) = (a + 1) <=? b | |
IsIntBaseSubType a b = False |
type IsIntTypeIso a b = IsIntBaseTypeIso (IntBaseType a) (IntBaseType b) Source
type family IsIntBaseTypeIso a b :: Bool Source
IsIntBaseTypeIso a a = True | |
IsIntBaseTypeIso (FixedIntTag n) (FixedWordTag n) = True | |
IsIntBaseTypeIso (FixedWordTag n) (FixedIntTag n) = True | |
IsIntBaseTypeIso a b = False |
type IsIntTypeEq a b = IsIntBaseTypeEq (IntBaseType a) (IntBaseType b) Source
type family IsIntBaseTypeEq a b :: Bool Source
IsIntBaseTypeEq a a = True | |
IsIntBaseTypeEq a b = False |