newsynth-0.3.0.1: Quantum/Synthesis/ToReal.hs
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Rank2Types #-}
-- | This module provides a type class of things that can be converted
-- to arbitrary precision real numbers.
module Quantum.Synthesis.ToReal where
import Quantum.Synthesis.ArcTan2
import Data.Number.FixedPrec
-- ----------------------------------------------------------------------
-- * Conversion to real number types
-- | A type class for things that can be converted to a real number at
-- arbitrary precision.
class ToReal a where
to_real :: (Floating r, ArcTan2 r) => a -> r
instance ToReal Rational where
to_real = fromRational
instance ToReal Integer where
to_real = fromInteger
instance ToReal Int where
to_real = fromIntegral
instance ToReal Double where
to_real = fromRational . toRational
instance ToReal Float where
to_real = fromRational . toRational
instance (Precision e) => ToReal (FixedPrec e) where
to_real = fromRational . toRational
-- ----------------------------------------------------------------------
-- ** Dynamic conversion to FixedPrec
-- | It would be useful to have a function for converting a symbolic
-- real number to a fixed-precision real number with a chosen
-- precision, such that the precision /e/ depends on a parameter /d/:
--
-- > to_fixedprec :: (ToReal r) => Integer -> r -> FixedPrec e
-- > to_fixedprec d x = ...
--
-- However, since /e/ is a type, /d/ is a term, and Haskell is not
-- dependently typed, this cannot be done directly.
--
-- The function 'dynamic_fixedprec' is the closest thing we have to a
-- workaround. The call @dynamic_fixedprec@ /d/ /f/ /x/ calls
-- /f/(/x/'), where /x/' is the value /x/ converted to /d/ digits of
-- precision. In other words, we have
--
-- > dynamic_fixedprec d f x = f (to_fixedprec d x),
--
-- with the restriction that the precision /e/ cannot occur freely in
-- the result type of /f/.
dynamic_fixedprec :: forall a r.(ToReal r) => Integer -> (forall e.(Precision e) => FixedPrec e -> a) -> r -> a
dynamic_fixedprec d f x = loop d (undefined :: P0)
where
loop :: forall e.(Precision e) => Integer -> e -> a
loop d e
| d >= 1000 = loop (d-1000) (undefined :: PPlus1000 e)
| d >= 100 = loop (d-100) (undefined :: PPlus100 e)
| d >= 10 = loop (d-10) (undefined :: PPlus10 e)
| d > 0 = loop (d-1) (undefined :: PPlus1 e)
| otherwise = f (to_real x :: FixedPrec e)
-- | Like 'dynamic_fixedprec', but take two real number arguments. In
-- terms of the fictitious function @to_fixedprec@, we have:
--
-- > dynamic_fixedprec2 d f x y = f (to_fixedprec d x) (to_fixedprec d y).
dynamic_fixedprec2 :: forall a r s.(ToReal r, ToReal s) => Integer -> (forall e.(Precision e) => FixedPrec e -> FixedPrec e -> a) -> r -> s -> a
dynamic_fixedprec2 d f x y = loop d (undefined :: P0)
where
loop :: forall e.(Precision e) => Integer -> e -> a
loop d e
| d >= 1000 = loop (d-1000) (undefined :: PPlus1000 e)
| d >= 100 = loop (d-100) (undefined :: PPlus100 e)
| d >= 10 = loop (d-10) (undefined :: PPlus10 e)
| d > 0 = loop (d-1) (undefined :: PPlus1 e)
| otherwise = f (to_real x :: FixedPrec e) (to_real y :: FixedPrec e)