Initial commit
[altfloat.git] / Data / Floating / Types.hs
blob5826ab07206e8045e37e9b05b3f2a3b5cc5f4b73
1 -- | This module provides an alternate definition of the floating point types
2 -- in Haskell.
3 {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, OverlappingInstances #-}
4 {-# LANGUAGE ForeignFunctionInterface, MagicHash #-}
5 {-# INCLUDE cfloat.h #-}
6 module Data.Floating.Types (
7 Float(..), Double(..), FloatConvert(..)
8 ) where
10 import Prelude hiding (Double, Float)
11 import qualified GHC.Exts as GHC
12 import GHC.Integer
13 import GHC.Prim
14 import Foreign.C
16 import Unsafe.Coerce
18 -- | For reasons unknown to me, we actually need to do foreign calls in order
19 -- to convert between floating types.
20 foreign import ccall unsafe "double_to_float"
21 double_to_float :: CDouble -> CFloat
22 -- | The opposite of double_to_float.
23 foreign import ccall unsafe "float_to_double"
24 float_to_double :: CFloat -> CDouble
26 -- | The Double type. This is expected to be an identical declaration to
27 -- the one found in GHC.Prim. We avoid simply using GHC's type because we need
28 -- to define our own class instances.
29 data Double = D# Double#
31 -- | The Float type.
32 data Float = F# Float#
34 -- | This type is identical to CDouble. For some reason unknown to me, it is
35 -- impossible to marshal data from Double to CDouble without losing
36 -- information. The issue is further complicated by Foreign.C.Types not
37 -- exporting CDouble's constructor. Thus, to marshal data from Double to
38 -- CDouble, we construct an instance of this type and then use unsafeCoerce.
39 newtype FuckFFIDouble = FuckD Double
41 -- | The analogue of FuckFFIDouble for CFloat.
42 newtype FuckFFIFloat = FuckF Float
44 -- | Coercion to floating point types.
45 class FloatConvert a b where
46 toFloating :: a -> b
48 instance FloatConvert Double CDouble where
49 toFloating = unsafeCoerce . FuckD
51 instance FloatConvert CDouble Double where
52 toFloating f = let FuckD x = unsafeCoerce f in x
54 instance FloatConvert Float CFloat where
55 toFloating = unsafeCoerce . FuckF
57 instance FloatConvert CFloat Float where
58 toFloating f = let FuckF x = unsafeCoerce f in x
60 instance FloatConvert Double Float where
61 toFloating = toFloating . double_to_float . toFloating
63 instance FloatConvert Float Double where
64 toFloating = toFloating . float_to_double . toFloating
66 instance Integral a => FloatConvert a Double where
67 toFloating x = D# (doubleFromInteger (toInteger x))
69 instance Integral a => FloatConvert a Float where
70 toFloating x = F# (floatFromInteger (toInteger x))
72 instance FloatConvert a a where
73 toFloating = id