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) as well
as the Natural
type.
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 |