Boolean-0.2.2: src/Data/Boolean/Numbers.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -Wall #-}
-------------------------------------------------------------------------
-- |
-- Module : Data.Boolean.Numbers
-- Copyright : (c) Jan Bracker 2013
-- License : BSD3
--
-- Maintainer : jbra@informatik.uni-kiel.de
-- Stability : experimental
--
-- A generalized version of the class hirarchy for numbers. All
-- functions that would break a potential deep embedding are removed
-- or generalized to support deep embeddings.
--
-- The class hierarchy for numeric types keeps as close as possible to the
-- 'Prelude' hierarchy. A great part of the default implementation and comments
-- are copied and adopted from 'Prelude'.
--
-------------------------------------------------------------------------
module Data.Boolean.Numbers
( NumB(..)
, IntegralB(..)
, RealFracB(..)
, RealFloatB(..)
, evenB, oddB
, fromIntegralB
) where
import Prelude hiding
( quotRem, divMod
, quot, rem
, div, mod
, properFraction
, fromInteger, toInteger )
import qualified Prelude as P
import Control.Arrow (first)
import Data.Boolean
{--------------------------------------------------------------------
Misc
--------------------------------------------------------------------}
infixr 9 .:
-- Double composition. (Aka "result.result". See semantic editor combinators.)
(.:) :: (c -> c') -> (a -> b -> c) -> (a -> b -> c')
(.:) = (.).(.)
(##) :: (a -> b -> c) -> (a -> b -> d) -> a -> b -> (c,d)
(f ## g) x y = (f x y, g x y)
-- -----------------------------------------------------------------------
-- Generalized Number Class Hirarchy
-- -----------------------------------------------------------------------
-- | An extension of 'Num' that supplies the integer type of a
-- given number type and a way to create that number from the
-- integer.
class Num a => NumB a where
-- | The accociated integer type of the number.
type IntegerOf a
-- | Construct the number from the associated integer.
fromIntegerB :: IntegerOf a -> a
-- | A deep embedded version of 'Integral'.
-- Integral numbers, supporting integer division.
--
-- Minimal complete definition is either 'quotRem' and 'divMod'
-- or the other four functions. Besides that 'toIntegerB' always
-- has to be implemented.
class (NumB a, OrdB a) => IntegralB a where
-- | Integer division truncated towards zero.
quot :: a -> a -> a
quot = fst .: quotRem
-- | Integer reminder, satisfying:
-- @(x `quot` y) * y + (x `rem` y) == x@
rem :: a -> a -> a
rem = snd .: quotRem
-- | Integer division truncated toward negative infinity.
div :: a -> a -> a
div = fst .: divMod
-- | Integer modulus, satisfying:
-- @(x `div` y) * y + (x `mod` y) == x@
mod :: a -> a -> a
mod = snd .: divMod
-- | Simultaneous 'quot' and 'rem'.
quotRem :: a -> a -> (a,a)
quotRem = quot ## rem
-- | Simultaneous 'div' and 'mod'.
divMod :: a -> a -> (a,a)
divMod = div ## mod
-- | Create a integer from this integral.
toIntegerB :: a -> IntegerOf a
-- | Deep embedded version of 'RealFloat'.
-- Extracting components of fractions.
--
-- Minimal complete definition: 'properFraction',
-- 'round', 'floor' and 'ceiling'.
class (NumB a, OrdB a, Fractional a) => RealFracB a where
-- | The function 'properFraction' takes a real fractional number @x@
-- and returns a pair @(n,f)@ such that @x = n+f@, and:
--
-- * @n@ is an integral number with the same sign as @x@; and
--
-- * @f@ is a fraction with the same type and sign as @x@,
-- and with absolute value less than @1@.
--
-- The default definitions of the 'ceiling', 'floor', 'truncate'
-- and 'round' functions are in terms of 'properFraction'.
properFraction :: (IntegerOf a ~ IntegerOf b, IntegralB b) => a -> (b, a)
-- | @'truncate' x@ returns the integer nearest @x@ between zero and @x@
truncate :: (IntegerOf a ~ IntegerOf b, IntegralB b) => a -> b
truncate = fst . properFraction
-- | @'round' x@ returns the nearest integer to @x@;
-- the even integer if @x@ is equidistant between two integers
round :: (IntegerOf a ~ IntegerOf b, IntegralB b) => a -> b
-- | @'ceiling' x@ returns the least integer not less than @x@
ceiling :: (IntegerOf a ~ IntegerOf b, IntegralB b) => a -> b
-- | @'floor' x@ returns the greatest integer not greater than @x@.
floor :: (IntegerOf a ~ IntegerOf b, IntegralB b) => a -> b
-- | Deep embedded version of 'RealFloat'.
-- Efficient, machine-independent access to the components of a
-- floating-point number.
--
-- A complete definition has to define all functions.
class (Boolean (BooleanOf a), RealFracB a, Floating a) => RealFloatB a where
-- | 'true' if the argument is an IEEE \"not-a-number\" (NaN) value.
isNaN :: a -> BooleanOf a
-- | 'true' if the argument is an IEEE infinity or negative infinity.
isInfinite :: a -> BooleanOf a
-- | 'true' if the argument is an IEEE negative zero.
isNegativeZero :: a -> BooleanOf a
-- | 'true' if the argument is an IEEE floating point number.
isIEEE :: a -> BooleanOf a
-- | a version of arctangent taking two real floating-point arguments.
-- For real floating @x@ and @y@, @'atan2' y x@ computes the angle
-- (from the positive x-axis) of the vector from the origin to the
-- point @(x,y)@. @'atan2' y x@ returns a value in the range [@-pi@,
-- @pi@]. It follows the Common Lisp semantics for the origin when
-- signed zeroes are supported. @'atan2' y 1@, with @y@ in a type
-- that is 'RealFloatB', should return the same value as @'atan' y@.
atan2 :: a -> a -> a
-- -----------------------------------------------------------------------
-- Generalized Number Utility Functions
-- -----------------------------------------------------------------------
-- | Variant of 'even' for generalized booleans.
evenB :: (IfB a, EqB a, IntegralB a) => a -> BooleanOf a
evenB n = n `rem` 2 ==* 0
-- | Variant of 'odd' for generalized booleans.
oddB :: (IfB a, EqB a, IntegralB a) => a -> BooleanOf a
oddB = notB . evenB
-- | Variant of 'fromIntegral' for generalized booleans.
fromIntegralB :: (IntegerOf a ~ IntegerOf b, IntegralB a, NumB b) => a -> b
fromIntegralB = fromIntegerB . toIntegerB
-- -----------------------------------------------------------------------
-- Default Class Instances for Basic Types
-- -----------------------------------------------------------------------
-- | Only for internal use.
fromInteger' :: (Integer ~ IntegerOf b, NumB b) => Integer -> b
fromInteger' = fromIntegralB
#define DefaultNumBInstance(Ty) \
instance NumB (Ty) where {\
type IntegerOf (Ty) = Integer ;\
fromIntegerB = P.fromInteger }
#define DefaultIntegralBInstance(Ty) \
instance IntegralB (Ty) where {\
quotRem = P.quotRem ;\
divMod = P.divMod ;\
toIntegerB = P.toInteger }
#define DefaultRealFracFloatBInstance(Ty) \
instance RealFracB (Ty) where {\
properFraction = first fromInteger' . P.properFraction ;\
round = fromInteger' . P.round ;\
floor = fromInteger' . P.floor ;\
ceiling = fromInteger' . P.ceiling };\
instance RealFloatB (Ty) where {\
isNaN = P.isNaN ;\
isInfinite = P.isInfinite ;\
isNegativeZero = P.isNegativeZero ;\
isIEEE = P.isIEEE ;\
atan2 = P.atan2 }
DefaultNumBInstance(Int)
DefaultNumBInstance(Integer)
DefaultNumBInstance(Float)
DefaultNumBInstance(Double)
DefaultIntegralBInstance(Int)
DefaultIntegralBInstance(Integer)
DefaultRealFracFloatBInstance(Float)
DefaultRealFracFloatBInstance(Double)