packages feed

exact-pi 0.2.1.2 → 0.3.0.0

raw patch · 4 files changed

+145/−3 lines, 4 filesdep +numtype-dkPVP ok

version bump matches the API change (PVP)

Dependencies added: numtype-dk

API changes (from Hackage documentation)

- Data.ExactPi: instance Floating ExactPi
- Data.ExactPi: instance Fractional ExactPi
- Data.ExactPi: instance Monoid ExactPi
- Data.ExactPi: instance Num ExactPi
- Data.ExactPi: instance Show ExactPi
+ Data.ExactPi: instance GHC.Base.Monoid Data.ExactPi.ExactPi
+ Data.ExactPi: instance GHC.Float.Floating Data.ExactPi.ExactPi
+ Data.ExactPi: instance GHC.Num.Num Data.ExactPi.ExactPi
+ Data.ExactPi: instance GHC.Real.Fractional Data.ExactPi.ExactPi
+ Data.ExactPi: instance GHC.Show.Show Data.ExactPi.ExactPi
+ Data.ExactPi: isExact :: ExactPi -> Bool
+ Data.ExactPi.TypeLevel: ExactPi' :: TypeInt -> Nat -> Nat -> ExactPi'
+ Data.ExactPi.TypeLevel: class KnownExactPi (v :: ExactPi')
+ Data.ExactPi.TypeLevel: data ExactPi'
+ Data.ExactPi.TypeLevel: exactPiVal :: KnownExactPi v => Proxy v -> ExactPi
+ Data.ExactPi.TypeLevel: injMin :: (KnownExactPi v, MinCtxt v a, KnownMinCtxt (MinCtxt v)) => Proxy v -> a
+ Data.ExactPi.TypeLevel: instance (Numeric.NumType.DK.Integers.KnownTypeInt z, GHC.TypeLits.KnownNat p, GHC.TypeLits.KnownNat q, 1 GHC.TypeLits.<= q) => Data.ExactPi.TypeLevel.KnownExactPi ('Data.ExactPi.TypeLevel.ExactPi' z p q)
+ Data.ExactPi.TypeLevel: instance Data.ExactPi.TypeLevel.KnownMinCtxt GHC.Float.Floating
+ Data.ExactPi.TypeLevel: instance Data.ExactPi.TypeLevel.KnownMinCtxt GHC.Num.Num
+ Data.ExactPi.TypeLevel: instance Data.ExactPi.TypeLevel.KnownMinCtxt GHC.Real.Fractional
+ Data.ExactPi.TypeLevel: type ExactNatural n = ExactPi' Zero n 1
+ Data.ExactPi.TypeLevel: type One = ExactNatural 1
+ Data.ExactPi.TypeLevel: type Pi = ExactPi' Pos1 1 1

Files

changelog.md view
@@ -1,3 +1,7 @@+0.3.0.0
+-------
+* Added a type-level representation of ExactPi values.
+
 0.2.1.2
 -------
 * Fixed a bug in recip.
exact-pi.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                exact-pi
-version:             0.2.1.2
+version:             0.3.0.0
 synopsis:            Exact rational multiples of pi (and integer powers of pi)
 description:         Provides an exact representation for rational multiples of pi alongside an approximate representation of all reals.
                      Useful for storing and computing with conversion factors between physical units.
@@ -19,10 +19,12 @@ cabal-version:       >=1.10
 
 library
-  exposed-modules:     Data.ExactPi
+  exposed-modules:     Data.ExactPi,
+                       Data.ExactPi.TypeLevel
   -- other-modules:       
   -- other-extensions:    
-  build-depends:       base >=4.7 && <4.9
+  build-depends:       base >=4.7 && <4.9,
+                       numtype-dk >= 0.5
   ghc-options:         -Wall
   hs-source-dirs:      src
   default-language:    Haskell2010
src/Data/ExactPi.hs view
@@ -20,6 +20,7 @@   ExactPi(..),
   approximateValue,
   isZero,
+  isExact,
   isExactZero,
   isExactOne,
   isExactInteger,
@@ -50,6 +51,11 @@ isZero (Exact _ 0)     = True
 isZero (Approximate x) = x == (0 :: Double)
 isZero _               = False
+
+-- | Identifies whether an 'ExactPi' is an exact value.
+isExact :: ExactPi -> Bool
+isExact (Exact _ _) = True
+isExact _           = False
 
 -- | Identifies whether an 'ExactPi' is an exact representation of zero.
 isExactZero :: ExactPi -> Bool
+ src/Data/ExactPi/TypeLevel.hs view
@@ -0,0 +1,130 @@+{-# OPTIONS_HADDOCK show-extensions #-}
+
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+
+{-|
+Module      : Data.ExactPi.TypeLevel
+Description : Exact non-negative rational multiples of powers of pi at the type level
+License     : MIT
+Maintainer  : douglas.mcclean@gmail.com
+Stability   : experimental
+
+This kind is sufficient to exactly express the closure of Q⁺ ∪ {π} under multiplication and division.
+As a result it is useful for representing conversion factors between physical units. 
+-}
+module Data.ExactPi.TypeLevel
+(
+  -- * Type Level ExactPi Values
+  type ExactPi'(..),
+  KnownExactPi(..),
+  -- * Arithmetic
+  type (*), type (/), type Recip,
+  type ExactNatural,
+  type One, type Pi,
+  -- * Conversion to Term Level
+  type MinCtxt,
+  injMin
+)
+where
+
+import Data.ExactPi
+import Data.Maybe (fromJust)
+import Data.Proxy
+import Data.Ratio
+import GHC.Exts (Constraint)
+import GHC.TypeLits hiding (type (*), type (^))
+import qualified GHC.TypeLits as N
+import Numeric.NumType.DK.Integers hiding (type (*), type (/))
+import qualified Numeric.NumType.DK.Integers as Z
+
+-- | A type-level representation of a non-negative rational multiple of an integer power of pi.
+--
+-- Each type in this kind can be exactly represented at the term level by a value of type 'ExactPi',
+-- provided that its denominator is non-zero.
+--
+-- Note that there are many representations of zero, and many representations of dividing by zero.
+-- These are not excluded because doing so introduces a lot of extra machinery. Play nice! Future
+-- versions may not include a representation for zero.
+--
+-- Of course there are also many representations of every value, because the numerator need not be
+-- comprime to the denominator. For many purposes it is not necessary to maintain the types in reduced
+-- form, they will be appropriately reduced when converted to terms.
+data ExactPi' = ExactPi' TypeInt -- Exponent of pi
+                         Nat -- Numerator
+                         Nat -- Denominator
+
+-- | A KnownDimension is one for which we can construct a term-level representation.
+--
+-- Each validly constructed type of kind 'ExactPi'' has a 'KnownExactPi' instance, provided that
+-- its denominator is non-zero.
+class KnownExactPi (v :: ExactPi') where
+  -- | Converts an 'ExactPi'' type to an 'ExactPi' value.
+  exactPiVal :: Proxy v -> ExactPi
+
+-- | Determines the minimum context required for a numeric type to hold the value
+-- associated with a specific 'ExactPi'' type.
+type family MinCtxt (v :: ExactPi') :: * -> Constraint where
+  MinCtxt ('ExactPi' 'Zero p 1) = Num
+  MinCtxt ('ExactPi' 'Zero p q) = Fractional
+  MinCtxt ('ExactPi' z p q)     = Floating
+
+-- | A KnownMinCtxt is a contraint on values sufficient to allow us to inject certain
+-- 'ExactPi' values into types that satisfy the constraint.
+class KnownMinCtxt (c :: * -> Constraint) where
+  -- | Injects an 'ExactPi' value into a specified type satisfying this constraint.
+  -- 
+  -- The injection is permitted to fail if type constraint does not entail the 'MinCtxt'
+  -- required by the 'ExactPi'' representation of the supplied 'ExactPi' value.
+  inj :: c a => Proxy c -- ^ A proxy for identifying the required constraint.
+             -> ExactPi -- ^ The value to inject.
+             -> a       -- ^ A value of the constrained type corresponding to the supplied 'ExactPi' value.
+
+instance KnownMinCtxt Num where
+  inj _ = fromInteger . fromJust . toExactInteger
+
+instance KnownMinCtxt Fractional where
+  inj _ = fromRational . fromJust . toExactRational
+
+instance KnownMinCtxt Floating where
+  inj _ = approximateValue
+
+-- | Converts an 'ExactPi'' type to a numeric value with the minimum required context.
+-- 
+-- When the value is known to be an integer, it can be returned as any instance of 'Num'. Similarly,
+-- rationals require 'Fractional', and values that involve 'pi' require 'Floating'.
+injMin :: forall v a.(KnownExactPi v, MinCtxt v a, KnownMinCtxt (MinCtxt v)) => Proxy v -> a
+injMin = inj (Proxy :: Proxy (MinCtxt v)) . exactPiVal
+
+instance (KnownTypeInt z, KnownNat p, KnownNat q, 1 <= q) => KnownExactPi ('ExactPi' z p q) where
+  exactPiVal _ = Exact z' (p' % q')
+    where
+      z' = toNum  (Proxy :: Proxy z)
+      p' = natVal (Proxy :: Proxy p)
+      q' = natVal (Proxy :: Proxy q)
+
+-- | Forms the product of 'ExactPi'' types (in the arithmetic sense).
+type family (a :: ExactPi') * (b :: ExactPi') :: ExactPi' where
+  ('ExactPi' z p q) * ('ExactPi' z' p' q') = 'ExactPi' (z Z.+ z') (p N.* p') (q N.* q')
+
+-- | Forms the quotient of 'ExactPi'' types (in the arithmetic sense).
+type family (a :: ExactPi') / (b :: ExactPi') :: ExactPi' where
+  ('ExactPi' z p q) / ('ExactPi' z' p' q') = 'ExactPi' (z Z.- z') (p N.* q') (q N.* p')
+
+-- | Forms the reciprocal of an 'ExactPi'' type.
+type family Recip (a :: ExactPi') :: ExactPi' where
+  Recip ('ExactPi' z p q) = 'ExactPi' (Negate z) q p
+
+-- | Converts a type-level natural to an 'ExactPi'' type.
+type ExactNatural n = 'ExactPi' 'Zero n 1
+
+-- | The 'ExactPi'' type representing the number 1.
+type One = ExactNatural 1
+
+-- | The 'ExactPi'' type representing the number 'pi'.
+type Pi = 'ExactPi' 'Pos1 1 1