{- |
    Copyright  : Copyright (C) 2006-2018 Bjorn Buckwalter
    License    : BSD3

    Maintainer : bjorn@buckwalter.se
    Stability  : Stable
    Portability: GHC only?

Defines types for manipulation of units and quantities without phantom types for their dimensions.
-}

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Numeric.Units.Dimensional.Dynamic
(
  -- * Dynamic Quantities
  AnyQuantity
, DynQuantity
, Demotable
, Promotable
, HasDynamicDimension(..), DynamicDimension(..)
, promoteQuantity, demoteQuantity
, (*~), (/~), invalidQuantity, polydimensionalZero
  -- * Dynamic Units
, AnyUnit
, demoteUnit, promoteUnit, demoteUnit'
, siUnit, anyUnitName
  -- ** Arithmetic on Dynamic Units
, (*), (/), (^), recip, applyPrefix
) where

import Control.DeepSeq
import Control.Monad
import Data.Data
import Data.ExactPi
import Data.Kind
import Data.Semigroup (Semigroup(..))
import Data.Monoid (Monoid(..))
import GHC.Generics
import Prelude (Eq(..), Num, Fractional, Floating, Show(..), Bool(..), Maybe(..), (.), ($), (++), (&&), id, otherwise, error)
import qualified Prelude as P
import Numeric.Units.Dimensional hiding ((*~), (/~), (*), (/), (^), recip, nroot, siUnit)
import qualified Numeric.Units.Dimensional as Dim
import Numeric.Units.Dimensional.Coercion
import Numeric.Units.Dimensional.UnitNames (UnitName, baseUnitName)
import qualified Numeric.Units.Dimensional.UnitNames.InterchangeNames as I
import qualified Numeric.Units.Dimensional.UnitNames as N
import Numeric.Units.Dimensional.Dimensions.TermLevel (HasDynamicDimension(..), DynamicDimension(..), matchDimensions, isCompatibleWith)
import qualified Numeric.Units.Dimensional.Dimensions.TermLevel as D

-- | The class of types that can be used to model 'Quantity's that are certain to have a value with
-- some dimension.
class Demotable (q :: Type -> Type) where
  demotableOut :: q a -> AnyQuantity a

-- | The class of types that can be used to model 'Quantity's whose 'Dimension's are
-- only known dynamically.
class Promotable (q :: Type -> Type) where
  promotableIn :: AnyQuantity a -> q a
  promotableOut :: q a -> DynQuantity a

-- | Forgets information about a 'Quantity' or 'AnyQuantity', yielding an 'AnyQuantity' or a 'DynQuantity'.
demoteQuantity :: (Demotable q, Promotable d) => q a -> d a
demoteQuantity :: q a -> d a
demoteQuantity = AnyQuantity a -> d a
forall (q :: Type -> Type) a. Promotable q => AnyQuantity a -> q a
promotableIn (AnyQuantity a -> d a) -> (q a -> AnyQuantity a) -> q a -> d a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. q a -> AnyQuantity a
forall (q :: Type -> Type) a. Demotable q => q a -> AnyQuantity a
demotableOut

-- | Converts a dynamic quantity such as an 'AnyQuantity' or a 'DynQuantity' into a
-- 'Quantity', or to 'Nothing' if the dynamic quantity cannot be represented in the
-- narrower result type.
promoteQuantity :: forall a d q.(Promotable q, KnownDimension d) => q a -> Maybe (Quantity d a)
promoteQuantity :: q a -> Maybe (Quantity d a)
promoteQuantity = DynQuantity a -> Maybe (Quantity d a)
forall a (s :: ExactPi') (d :: Dimension).
DynQuantity a -> Maybe (Dimensional ('DQuantity s) d a)
promoteQ (DynQuantity a -> Maybe (Quantity d a))
-> (q a -> DynQuantity a) -> q a -> Maybe (Quantity d a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. q a -> DynQuantity a
forall (q :: Type -> Type) a. Promotable q => q a -> DynQuantity a
promotableOut
  where
    dim' :: Dimension'
dim' = Proxy d -> Dimension'
forall a. HasDimension a => a -> Dimension'
dimension (Proxy d
forall k (t :: k). Proxy t
Proxy :: Proxy d)
    promoteQ :: DynQuantity a -> Maybe (Dimensional ('DQuantity s) d a)
promoteQ (DynQuantity DynamicDimension
d a
v) | DynamicDimension
d DynamicDimension -> Dimension' -> Bool
forall a. HasDynamicDimension a => a -> Dimension' -> Bool
`isCompatibleWith` Dimension'
dim' = Dimensional ('DQuantity s) d a
-> Maybe (Dimensional ('DQuantity s) d a)
forall a. a -> Maybe a
Just (Dimensional ('DQuantity s) d a
 -> Maybe (Dimensional ('DQuantity s) d a))
-> (a -> Dimensional ('DQuantity s) d a)
-> a
-> Maybe (Dimensional ('DQuantity s) d a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Dimensional ('DQuantity s) d a
forall (s :: ExactPi') (d :: Dimension) a.
a -> Dimensional ('DQuantity s) d a
Quantity (a -> Maybe (Dimensional ('DQuantity s) d a))
-> a -> Maybe (Dimensional ('DQuantity s) d a)
forall a b. (a -> b) -> a -> b
$ a
v
                               | Bool
otherwise                 = Maybe (Dimensional ('DQuantity s) d a)
forall a. Maybe a
Nothing

instance (KnownDimension d) => Demotable (Quantity d) where
  demotableOut :: Quantity d a -> AnyQuantity a
demotableOut q :: Quantity d a
q@(Quantity x) = Dimension' -> a -> AnyQuantity a
forall a. Dimension' -> a -> AnyQuantity a
AnyQuantity (Quantity d a -> Dimension'
forall a. HasDimension a => a -> Dimension'
dimension Quantity d a
q) a
x

-- | A 'Quantity' whose 'Dimension' is only known dynamically.
data AnyQuantity a = AnyQuantity !Dimension' !a
  deriving (AnyQuantity a -> AnyQuantity a -> Bool
(AnyQuantity a -> AnyQuantity a -> Bool)
-> (AnyQuantity a -> AnyQuantity a -> Bool) -> Eq (AnyQuantity a)
forall a. Eq a => AnyQuantity a -> AnyQuantity a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AnyQuantity a -> AnyQuantity a -> Bool
$c/= :: forall a. Eq a => AnyQuantity a -> AnyQuantity a -> Bool
== :: AnyQuantity a -> AnyQuantity a -> Bool
$c== :: forall a. Eq a => AnyQuantity a -> AnyQuantity a -> Bool
Eq, Typeable (AnyQuantity a)
DataType
Constr
Typeable (AnyQuantity a)
-> (forall (c :: Type -> Type).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> AnyQuantity a -> c (AnyQuantity a))
-> (forall (c :: Type -> Type).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c (AnyQuantity a))
-> (AnyQuantity a -> Constr)
-> (AnyQuantity a -> DataType)
-> (forall (t :: Type -> Type) (c :: Type -> Type).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c (AnyQuantity a)))
-> (forall (t :: Type -> Type -> Type) (c :: Type -> Type).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e))
    -> Maybe (c (AnyQuantity a)))
-> ((forall b. Data b => b -> b) -> AnyQuantity a -> AnyQuantity a)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r)
-> (forall u. (forall d. Data d => d -> u) -> AnyQuantity a -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> AnyQuantity a -> u)
-> (forall (m :: Type -> Type).
    Monad m =>
    (forall d. Data d => d -> m d)
    -> AnyQuantity a -> m (AnyQuantity a))
-> (forall (m :: Type -> Type).
    MonadPlus m =>
    (forall d. Data d => d -> m d)
    -> AnyQuantity a -> m (AnyQuantity a))
-> (forall (m :: Type -> Type).
    MonadPlus m =>
    (forall d. Data d => d -> m d)
    -> AnyQuantity a -> m (AnyQuantity a))
-> Data (AnyQuantity a)
AnyQuantity a -> DataType
AnyQuantity a -> Constr
(forall d. Data d => c (t d)) -> Maybe (c (AnyQuantity a))
(forall b. Data b => b -> b) -> AnyQuantity a -> AnyQuantity a
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AnyQuantity a -> c (AnyQuantity a)
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AnyQuantity a)
forall a. Data a => Typeable (AnyQuantity a)
forall a. Data a => AnyQuantity a -> DataType
forall a. Data a => AnyQuantity a -> Constr
forall a.
Data a =>
(forall b. Data b => b -> b) -> AnyQuantity a -> AnyQuantity a
forall a u.
Data a =>
Int -> (forall d. Data d => d -> u) -> AnyQuantity a -> u
forall a u.
Data a =>
(forall d. Data d => d -> u) -> AnyQuantity a -> [u]
forall a r r'.
Data a =>
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r
forall a r r'.
Data a =>
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r
forall a (m :: Type -> Type).
(Data a, Monad m) =>
(forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
forall a (m :: Type -> Type).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
forall a (c :: Type -> Type).
Data a =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AnyQuantity a)
forall a (c :: Type -> Type).
Data a =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AnyQuantity a -> c (AnyQuantity a)
forall a (t :: Type -> Type) (c :: Type -> Type).
(Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (AnyQuantity a))
forall a (t :: Type -> Type -> Type) (c :: Type -> Type).
(Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (AnyQuantity a))
forall a.
Typeable a
-> (forall (c :: Type -> Type).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: Type -> Type).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: Type -> Type) (c :: Type -> Type).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: Type -> Type -> Type) (c :: Type -> Type).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: Type -> Type).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: Type -> Type).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: Type -> Type).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> AnyQuantity a -> u
forall u. (forall d. Data d => d -> u) -> AnyQuantity a -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r
forall (m :: Type -> Type).
Monad m =>
(forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
forall (m :: Type -> Type).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
forall (c :: Type -> Type).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AnyQuantity a)
forall (c :: Type -> Type).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AnyQuantity a -> c (AnyQuantity a)
forall (t :: Type -> Type) (c :: Type -> Type).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c (AnyQuantity a))
forall (t :: Type -> Type -> Type) (c :: Type -> Type).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (AnyQuantity a))
$cAnyQuantity :: Constr
$tAnyQuantity :: DataType
gmapMo :: (forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
$cgmapMo :: forall a (m :: Type -> Type).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
gmapMp :: (forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
$cgmapMp :: forall a (m :: Type -> Type).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
gmapM :: (forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
$cgmapM :: forall a (m :: Type -> Type).
(Data a, Monad m) =>
(forall d. Data d => d -> m d)
-> AnyQuantity a -> m (AnyQuantity a)
gmapQi :: Int -> (forall d. Data d => d -> u) -> AnyQuantity a -> u
$cgmapQi :: forall a u.
Data a =>
Int -> (forall d. Data d => d -> u) -> AnyQuantity a -> u
gmapQ :: (forall d. Data d => d -> u) -> AnyQuantity a -> [u]
$cgmapQ :: forall a u.
Data a =>
(forall d. Data d => d -> u) -> AnyQuantity a -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r
$cgmapQr :: forall a r r'.
Data a =>
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r
$cgmapQl :: forall a r r'.
Data a =>
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> AnyQuantity a -> r
gmapT :: (forall b. Data b => b -> b) -> AnyQuantity a -> AnyQuantity a
$cgmapT :: forall a.
Data a =>
(forall b. Data b => b -> b) -> AnyQuantity a -> AnyQuantity a
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (AnyQuantity a))
$cdataCast2 :: forall a (t :: Type -> Type -> Type) (c :: Type -> Type).
(Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (AnyQuantity a))
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c (AnyQuantity a))
$cdataCast1 :: forall a (t :: Type -> Type) (c :: Type -> Type).
(Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (AnyQuantity a))
dataTypeOf :: AnyQuantity a -> DataType
$cdataTypeOf :: forall a. Data a => AnyQuantity a -> DataType
toConstr :: AnyQuantity a -> Constr
$ctoConstr :: forall a. Data a => AnyQuantity a -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AnyQuantity a)
$cgunfold :: forall a (c :: Type -> Type).
Data a =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (AnyQuantity a)
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AnyQuantity a -> c (AnyQuantity a)
$cgfoldl :: forall a (c :: Type -> Type).
Data a =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> AnyQuantity a -> c (AnyQuantity a)
$cp1Data :: forall a. Data a => Typeable (AnyQuantity a)
Data, (forall x. AnyQuantity a -> Rep (AnyQuantity a) x)
-> (forall x. Rep (AnyQuantity a) x -> AnyQuantity a)
-> Generic (AnyQuantity a)
forall x. Rep (AnyQuantity a) x -> AnyQuantity a
forall x. AnyQuantity a -> Rep (AnyQuantity a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (AnyQuantity a) x -> AnyQuantity a
forall a x. AnyQuantity a -> Rep (AnyQuantity a) x
$cto :: forall a x. Rep (AnyQuantity a) x -> AnyQuantity a
$cfrom :: forall a x. AnyQuantity a -> Rep (AnyQuantity a) x
Generic, (forall a. AnyQuantity a -> Rep1 AnyQuantity a)
-> (forall a. Rep1 AnyQuantity a -> AnyQuantity a)
-> Generic1 AnyQuantity
forall a. Rep1 AnyQuantity a -> AnyQuantity a
forall a. AnyQuantity a -> Rep1 AnyQuantity a
forall k (f :: k -> Type).
(forall (a :: k). f a -> Rep1 f a)
-> (forall (a :: k). Rep1 f a -> f a) -> Generic1 f
$cto1 :: forall a. Rep1 AnyQuantity a -> AnyQuantity a
$cfrom1 :: forall a. AnyQuantity a -> Rep1 AnyQuantity a
Generic1, Typeable)

instance (Show a) => Show (AnyQuantity a) where
  show :: AnyQuantity a -> String
show (AnyQuantity Dimension'
d a
a) | Dimension'
d Dimension' -> Dimension' -> Bool
forall a. Eq a => a -> a -> Bool
== Dimension'
D.dOne = a -> String
forall a. Show a => a -> String
show a
a
                         | Bool
otherwise   = a -> String
forall a. Show a => a -> String
show a
a String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ (UnitName 'NonMetric -> String
forall a. Show a => a -> String
show (UnitName 'NonMetric -> String)
-> (Dimension' -> UnitName 'NonMetric) -> Dimension' -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension' -> UnitName 'NonMetric
baseUnitName (Dimension' -> String) -> Dimension' -> String
forall a b. (a -> b) -> a -> b
$ Dimension'
d)

instance HasDynamicDimension (AnyQuantity a) where

instance HasDimension (AnyQuantity a) where
  dimension :: AnyQuantity a -> Dimension'
dimension (AnyQuantity Dimension'
d a
_) = Dimension'
d

instance NFData a => NFData (AnyQuantity a) -- instance is derived from Generic instance

instance Promotable AnyQuantity where
  promotableIn :: AnyQuantity a -> AnyQuantity a
promotableIn = AnyQuantity a -> AnyQuantity a
forall a. a -> a
id
  promotableOut :: AnyQuantity a -> DynQuantity a
promotableOut (AnyQuantity Dimension'
d a
a) = DynamicDimension -> a -> DynQuantity a
forall a. DynamicDimension -> a -> DynQuantity a
DynQuantity (Dimension' -> DynamicDimension
SomeDimension Dimension'
d) a
a

instance Demotable AnyQuantity where
  demotableOut :: AnyQuantity a -> AnyQuantity a
demotableOut = AnyQuantity a -> AnyQuantity a
forall a. a -> a
id

-- | 'AnyQuantity's form a 'Semigroup' under multiplication, but not under addition because
-- they may not be added together if their dimensions do not match.
instance Num a => Semigroup (AnyQuantity a) where
  (AnyQuantity Dimension'
d1 a
a1) <> :: AnyQuantity a -> AnyQuantity a -> AnyQuantity a
<> (AnyQuantity Dimension'
d2 a
a2) = Dimension' -> a -> AnyQuantity a
forall a. Dimension' -> a -> AnyQuantity a
AnyQuantity (Dimension'
d1 Dimension' -> Dimension' -> Dimension'
D.* Dimension'
d2) (a
a1 a -> a -> a
forall a. Num a => a -> a -> a
P.* a
a2)

-- | 'AnyQuantity's form a 'Monoid' under multiplication, but not under addition because
-- they may not be added together if their dimensions do not match.
instance Num a => Monoid (AnyQuantity a) where
  mempty :: AnyQuantity a
mempty = Dimensional ('DQuantity One) DOne a -> AnyQuantity a
forall (q :: Type -> Type) (d :: Type -> Type) a.
(Demotable q, Promotable d) =>
q a -> d a
demoteQuantity (a
1 a -> Unit 'NonMetric DOne a -> Dimensional ('DQuantity One) DOne a
forall a (m :: Metricality) (d :: Dimension).
Num a =>
a -> Unit m d a -> Quantity d a
Dim.*~ Unit 'NonMetric DOne a
forall a. Num a => Unit 'NonMetric DOne a
one)
  mappend :: AnyQuantity a -> AnyQuantity a -> AnyQuantity a
mappend = AnyQuantity a -> AnyQuantity a -> AnyQuantity a
forall a. Semigroup a => a -> a -> a
(Data.Semigroup.<>)

-- | Possibly a 'Quantity' whose 'Dimension' is only known dynamically.
--
-- By modeling the absence of a value, this type differs from 'AnyQuantity' in that it may
-- not be a 'Quantity' of any 'Dimension' whatsoever, but in exchange it gains instances
-- for the common numeric classes. It's therefore useful for manipulating, and not merely storing,
-- quantities of unknown dimension.
--
-- This type also contains a 'polydimensionalZero', representing zero value of any dimension.
--
-- Note that the 'Eq' instance for 'DynQuantity' equates all representations of an invalid value,
-- and also does not equate polydimensional zero with zero of any specific dimension.
data DynQuantity a = DynQuantity !DynamicDimension a -- we can't have strictness annotation on a as it is sometimes undefined
  deriving (Typeable (DynQuantity a)
DataType
Constr
Typeable (DynQuantity a)
-> (forall (c :: Type -> Type).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> DynQuantity a -> c (DynQuantity a))
-> (forall (c :: Type -> Type).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c (DynQuantity a))
-> (DynQuantity a -> Constr)
-> (DynQuantity a -> DataType)
-> (forall (t :: Type -> Type) (c :: Type -> Type).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c (DynQuantity a)))
-> (forall (t :: Type -> Type -> Type) (c :: Type -> Type).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e))
    -> Maybe (c (DynQuantity a)))
-> ((forall b. Data b => b -> b) -> DynQuantity a -> DynQuantity a)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r)
-> (forall u. (forall d. Data d => d -> u) -> DynQuantity a -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> DynQuantity a -> u)
-> (forall (m :: Type -> Type).
    Monad m =>
    (forall d. Data d => d -> m d)
    -> DynQuantity a -> m (DynQuantity a))
-> (forall (m :: Type -> Type).
    MonadPlus m =>
    (forall d. Data d => d -> m d)
    -> DynQuantity a -> m (DynQuantity a))
-> (forall (m :: Type -> Type).
    MonadPlus m =>
    (forall d. Data d => d -> m d)
    -> DynQuantity a -> m (DynQuantity a))
-> Data (DynQuantity a)
DynQuantity a -> DataType
DynQuantity a -> Constr
(forall d. Data d => c (t d)) -> Maybe (c (DynQuantity a))
(forall b. Data b => b -> b) -> DynQuantity a -> DynQuantity a
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> DynQuantity a -> c (DynQuantity a)
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (DynQuantity a)
forall a. Data a => Typeable (DynQuantity a)
forall a. Data a => DynQuantity a -> DataType
forall a. Data a => DynQuantity a -> Constr
forall a.
Data a =>
(forall b. Data b => b -> b) -> DynQuantity a -> DynQuantity a
forall a u.
Data a =>
Int -> (forall d. Data d => d -> u) -> DynQuantity a -> u
forall a u.
Data a =>
(forall d. Data d => d -> u) -> DynQuantity a -> [u]
forall a r r'.
Data a =>
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r
forall a r r'.
Data a =>
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r
forall a (m :: Type -> Type).
(Data a, Monad m) =>
(forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
forall a (m :: Type -> Type).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
forall a (c :: Type -> Type).
Data a =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (DynQuantity a)
forall a (c :: Type -> Type).
Data a =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> DynQuantity a -> c (DynQuantity a)
forall a (t :: Type -> Type) (c :: Type -> Type).
(Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (DynQuantity a))
forall a (t :: Type -> Type -> Type) (c :: Type -> Type).
(Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (DynQuantity a))
forall a.
Typeable a
-> (forall (c :: Type -> Type).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: Type -> Type).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: Type -> Type) (c :: Type -> Type).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: Type -> Type -> Type) (c :: Type -> Type).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: Type -> Type).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: Type -> Type).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: Type -> Type).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> DynQuantity a -> u
forall u. (forall d. Data d => d -> u) -> DynQuantity a -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r
forall (m :: Type -> Type).
Monad m =>
(forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
forall (m :: Type -> Type).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
forall (c :: Type -> Type).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (DynQuantity a)
forall (c :: Type -> Type).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> DynQuantity a -> c (DynQuantity a)
forall (t :: Type -> Type) (c :: Type -> Type).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c (DynQuantity a))
forall (t :: Type -> Type -> Type) (c :: Type -> Type).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (DynQuantity a))
$cDynQuantity :: Constr
$tDynQuantity :: DataType
gmapMo :: (forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
$cgmapMo :: forall a (m :: Type -> Type).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
gmapMp :: (forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
$cgmapMp :: forall a (m :: Type -> Type).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
gmapM :: (forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
$cgmapM :: forall a (m :: Type -> Type).
(Data a, Monad m) =>
(forall d. Data d => d -> m d)
-> DynQuantity a -> m (DynQuantity a)
gmapQi :: Int -> (forall d. Data d => d -> u) -> DynQuantity a -> u
$cgmapQi :: forall a u.
Data a =>
Int -> (forall d. Data d => d -> u) -> DynQuantity a -> u
gmapQ :: (forall d. Data d => d -> u) -> DynQuantity a -> [u]
$cgmapQ :: forall a u.
Data a =>
(forall d. Data d => d -> u) -> DynQuantity a -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r
$cgmapQr :: forall a r r'.
Data a =>
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r
$cgmapQl :: forall a r r'.
Data a =>
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> DynQuantity a -> r
gmapT :: (forall b. Data b => b -> b) -> DynQuantity a -> DynQuantity a
$cgmapT :: forall a.
Data a =>
(forall b. Data b => b -> b) -> DynQuantity a -> DynQuantity a
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (DynQuantity a))
$cdataCast2 :: forall a (t :: Type -> Type -> Type) (c :: Type -> Type).
(Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (DynQuantity a))
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c (DynQuantity a))
$cdataCast1 :: forall a (t :: Type -> Type) (c :: Type -> Type).
(Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (DynQuantity a))
dataTypeOf :: DynQuantity a -> DataType
$cdataTypeOf :: forall a. Data a => DynQuantity a -> DataType
toConstr :: DynQuantity a -> Constr
$ctoConstr :: forall a. Data a => DynQuantity a -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (DynQuantity a)
$cgunfold :: forall a (c :: Type -> Type).
Data a =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (DynQuantity a)
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> DynQuantity a -> c (DynQuantity a)
$cgfoldl :: forall a (c :: Type -> Type).
Data a =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> DynQuantity a -> c (DynQuantity a)
$cp1Data :: forall a. Data a => Typeable (DynQuantity a)
Data, (forall x. DynQuantity a -> Rep (DynQuantity a) x)
-> (forall x. Rep (DynQuantity a) x -> DynQuantity a)
-> Generic (DynQuantity a)
forall x. Rep (DynQuantity a) x -> DynQuantity a
forall x. DynQuantity a -> Rep (DynQuantity a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (DynQuantity a) x -> DynQuantity a
forall a x. DynQuantity a -> Rep (DynQuantity a) x
$cto :: forall a x. Rep (DynQuantity a) x -> DynQuantity a
$cfrom :: forall a x. DynQuantity a -> Rep (DynQuantity a) x
Generic, (forall a. DynQuantity a -> Rep1 DynQuantity a)
-> (forall a. Rep1 DynQuantity a -> DynQuantity a)
-> Generic1 DynQuantity
forall a. Rep1 DynQuantity a -> DynQuantity a
forall a. DynQuantity a -> Rep1 DynQuantity a
forall k (f :: k -> Type).
(forall (a :: k). f a -> Rep1 f a)
-> (forall (a :: k). Rep1 f a -> f a) -> Generic1 f
$cto1 :: forall a. Rep1 DynQuantity a -> DynQuantity a
$cfrom1 :: forall a. DynQuantity a -> Rep1 DynQuantity a
Generic1, Typeable)

instance Eq a => Eq (DynQuantity a) where
  (DynQuantity DynamicDimension
NoDimension a
_) == :: DynQuantity a -> DynQuantity a -> Bool
== (DynQuantity DynamicDimension
NoDimension a
_) = Bool
True -- all invalid quantities are equal
  (DynQuantity DynamicDimension
NoDimension a
_) == DynQuantity a
_                           = Bool
False -- invalid quanties are not equal to any other quantity
  DynQuantity a
_                           == (DynQuantity DynamicDimension
NoDimension a
_) = Bool
False
  (DynQuantity DynamicDimension
d1 a
v1)         == (DynQuantity DynamicDimension
d2 a
v2)         = DynamicDimension
d1 DynamicDimension -> DynamicDimension -> Bool
forall a. Eq a => a -> a -> Bool
== DynamicDimension
d2 Bool -> Bool -> Bool
&& a
v1 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
v2

instance NFData a => NFData (DynQuantity a) -- instance is derived from Generic instance

instance Show a => Show (DynQuantity a) where
  show :: DynQuantity a -> String
show (DynQuantity DynamicDimension
NoDimension a
_) = String
"invalidQuantity"
  show (DynQuantity DynamicDimension
AnyDimension a
v) = a -> String
forall a. Show a => a -> String
show a
v
  show (DynQuantity (SomeDimension Dimension'
d) a
v) = AnyQuantity a -> String
forall a. Show a => a -> String
show (AnyQuantity a -> String) -> AnyQuantity a -> String
forall a b. (a -> b) -> a -> b
$ Dimension' -> a -> AnyQuantity a
forall a. Dimension' -> a -> AnyQuantity a
AnyQuantity Dimension'
d a
v

instance Promotable DynQuantity where
  promotableIn :: AnyQuantity a -> DynQuantity a
promotableIn (AnyQuantity Dimension'
d a
a) = DynamicDimension -> a -> DynQuantity a
forall a. DynamicDimension -> a -> DynQuantity a
DynQuantity (Dimension' -> DynamicDimension
SomeDimension Dimension'
d) a
a
  promotableOut :: DynQuantity a -> DynQuantity a
promotableOut = DynQuantity a -> DynQuantity a
forall a. a -> a
id

instance HasDynamicDimension (DynQuantity a) where
  dynamicDimension :: DynQuantity a -> DynamicDimension
dynamicDimension (DynQuantity DynamicDimension
d a
_) = DynamicDimension
d

instance Num a => Num (DynQuantity a) where
  DynQuantity a
x + :: DynQuantity a -> DynQuantity a -> DynQuantity a
+ DynQuantity a
y = (DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
liftDQ2 DynamicDimension -> DynamicDimension -> DynamicDimension
matchDimensions a -> a -> a
forall a. Num a => a -> a -> a
(P.+) DynQuantity a
x DynQuantity a
y
  DynQuantity a
x - :: DynQuantity a -> DynQuantity a -> DynQuantity a
- DynQuantity a
y = (DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
liftDQ2 DynamicDimension -> DynamicDimension -> DynamicDimension
matchDimensions a -> a -> a
forall a. Num a => a -> a -> a
(P.-) DynQuantity a
x DynQuantity a
y
  DynQuantity a
x * :: DynQuantity a -> DynQuantity a -> DynQuantity a
* DynQuantity a
y = (DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
liftDQ2 ((Dimension' -> Dimension' -> Dimension')
-> DynamicDimension -> DynamicDimension -> DynamicDimension
valid2 Dimension' -> Dimension' -> Dimension'
(D.*)) a -> a -> a
forall a. Num a => a -> a -> a
(P.*) DynQuantity a
x DynQuantity a
y
  negate :: DynQuantity a -> DynQuantity a
negate = (DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
liftDQ DynamicDimension -> DynamicDimension
forall a. a -> a
id a -> a
forall a. Num a => a -> a
P.negate
  abs :: DynQuantity a -> DynQuantity a
abs = (DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
liftDQ DynamicDimension -> DynamicDimension
forall a. a -> a
id a -> a
forall a. Num a => a -> a
P.abs
  signum :: DynQuantity a -> DynQuantity a
signum = (DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
liftDQ (Dimension' -> DynamicDimension -> DynamicDimension
constant Dimension'
D.dOne) a -> a
forall a. Num a => a -> a
P.signum
  fromInteger :: Integer -> DynQuantity a
fromInteger = Dimensional ('DQuantity One) DOne a -> DynQuantity a
forall (q :: Type -> Type) (d :: Type -> Type) a.
(Demotable q, Promotable d) =>
q a -> d a
demoteQuantity (Dimensional ('DQuantity One) DOne a -> DynQuantity a)
-> (Integer -> Dimensional ('DQuantity One) DOne a)
-> Integer
-> DynQuantity a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Unit 'NonMetric DOne a -> Dimensional ('DQuantity One) DOne a
forall a (m :: Metricality) (d :: Dimension).
Num a =>
a -> Unit m d a -> Quantity d a
Dim.*~ Unit 'NonMetric DOne a
forall a. Num a => Unit 'NonMetric DOne a
one) (a -> Dimensional ('DQuantity One) DOne a)
-> (Integer -> a) -> Integer -> Dimensional ('DQuantity One) DOne a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> a
forall a. Num a => Integer -> a
P.fromInteger

instance Fractional a => Fractional (DynQuantity a) where
  DynQuantity a
x / :: DynQuantity a -> DynQuantity a -> DynQuantity a
/ DynQuantity a
y = (DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
liftDQ2 ((Dimension' -> Dimension' -> Dimension')
-> DynamicDimension -> DynamicDimension -> DynamicDimension
valid2 Dimension' -> Dimension' -> Dimension'
(D./)) a -> a -> a
forall a. Fractional a => a -> a -> a
(P./) DynQuantity a
x DynQuantity a
y
  recip :: DynQuantity a -> DynQuantity a
recip = (DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
liftDQ ((Dimension' -> Dimension') -> DynamicDimension -> DynamicDimension
valid Dimension' -> Dimension'
D.recip) a -> a
forall a. Fractional a => a -> a
P.recip
  fromRational :: Rational -> DynQuantity a
fromRational = Dimensional ('DQuantity One) DOne a -> DynQuantity a
forall (q :: Type -> Type) (d :: Type -> Type) a.
(Demotable q, Promotable d) =>
q a -> d a
demoteQuantity (Dimensional ('DQuantity One) DOne a -> DynQuantity a)
-> (Rational -> Dimensional ('DQuantity One) DOne a)
-> Rational
-> DynQuantity a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Unit 'NonMetric DOne a -> Dimensional ('DQuantity One) DOne a
forall a (m :: Metricality) (d :: Dimension).
Num a =>
a -> Unit m d a -> Quantity d a
Dim.*~ Unit 'NonMetric DOne a
forall a. Num a => Unit 'NonMetric DOne a
one) (a -> Dimensional ('DQuantity One) DOne a)
-> (Rational -> a)
-> Rational
-> Dimensional ('DQuantity One) DOne a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rational -> a
forall a. Fractional a => Rational -> a
P.fromRational

instance Floating a => Floating (DynQuantity a) where
  pi :: DynQuantity a
pi = Dimensional ('DQuantity One) DOne a -> DynQuantity a
forall (q :: Type -> Type) (d :: Type -> Type) a.
(Demotable q, Promotable d) =>
q a -> d a
demoteQuantity Dimensional ('DQuantity One) DOne a
forall a. Floating a => Dimensionless a
pi
  exp :: DynQuantity a -> DynQuantity a
exp = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.exp
  log :: DynQuantity a -> DynQuantity a
log = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.log
  sqrt :: DynQuantity a -> DynQuantity a
sqrt = (DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
liftDQ ((Dimension' -> Maybe Dimension')
-> DynamicDimension -> DynamicDimension
whenValid ((Dimension' -> Maybe Dimension')
 -> DynamicDimension -> DynamicDimension)
-> (Dimension' -> Maybe Dimension')
-> DynamicDimension
-> DynamicDimension
forall a b. (a -> b) -> a -> b
$ Int -> Dimension' -> Maybe Dimension'
D.nroot Int
2) a -> a
forall a. Floating a => a -> a
P.sqrt
  ** :: DynQuantity a -> DynQuantity a -> DynQuantity a
(**) = (DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
liftDQ2 (DynamicDimension
-> DynamicDimension -> DynamicDimension -> DynamicDimension
matchDimensions3 (DynamicDimension
 -> DynamicDimension -> DynamicDimension -> DynamicDimension)
-> DynamicDimension
-> DynamicDimension
-> DynamicDimension
-> DynamicDimension
forall a b. (a -> b) -> a -> b
$ Dimension' -> DynamicDimension
SomeDimension Dimension'
D.dOne) a -> a -> a
forall a. Floating a => a -> a -> a
(P.**)
  logBase :: DynQuantity a -> DynQuantity a -> DynQuantity a
logBase = (DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
liftDQ2 (DynamicDimension
-> DynamicDimension -> DynamicDimension -> DynamicDimension
matchDimensions3 (DynamicDimension
 -> DynamicDimension -> DynamicDimension -> DynamicDimension)
-> DynamicDimension
-> DynamicDimension
-> DynamicDimension
-> DynamicDimension
forall a b. (a -> b) -> a -> b
$ Dimension' -> DynamicDimension
SomeDimension Dimension'
D.dOne) a -> a -> a
forall a. Floating a => a -> a -> a
P.logBase
  sin :: DynQuantity a -> DynQuantity a
sin = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.sin
  cos :: DynQuantity a -> DynQuantity a
cos = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.cos
  tan :: DynQuantity a -> DynQuantity a
tan = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.tan
  asin :: DynQuantity a -> DynQuantity a
asin = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.asin
  acos :: DynQuantity a -> DynQuantity a
acos = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.acos
  atan :: DynQuantity a -> DynQuantity a
atan = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.atan
  sinh :: DynQuantity a -> DynQuantity a
sinh = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.sinh
  cosh :: DynQuantity a -> DynQuantity a
cosh = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.cosh
  tanh :: DynQuantity a -> DynQuantity a
tanh = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.tanh
  asinh :: DynQuantity a -> DynQuantity a
asinh = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.asinh
  acosh :: DynQuantity a -> DynQuantity a
acosh = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.acosh
  atanh :: DynQuantity a -> DynQuantity a
atanh = (a -> a) -> DynQuantity a -> DynQuantity a
forall a. (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless a -> a
forall a. Floating a => a -> a
P.atanh

-- | 'DynQuantity's form a 'Semigroup' under multiplication, but not under addition because
-- they may not be added together if their dimensions do not match.
instance Num a => Semigroup (DynQuantity a) where
    <> :: DynQuantity a -> DynQuantity a -> DynQuantity a
(<>) = DynQuantity a -> DynQuantity a -> DynQuantity a
forall a. Num a => a -> a -> a
(P.*)

-- | 'DynQuantity's form a 'Monoid' under multiplication, but not under addition because
-- they may not be added together if their dimensions do not match.
instance Num a => Monoid (DynQuantity a) where
  mempty :: DynQuantity a
mempty = Dimensional ('DQuantity One) DOne a -> DynQuantity a
forall (q :: Type -> Type) (d :: Type -> Type) a.
(Demotable q, Promotable d) =>
q a -> d a
demoteQuantity (a
1 a -> Unit 'NonMetric DOne a -> Dimensional ('DQuantity One) DOne a
forall a (m :: Metricality) (d :: Dimension).
Num a =>
a -> Unit m d a -> Quantity d a
Dim.*~ Unit 'NonMetric DOne a
forall a. Num a => Unit 'NonMetric DOne a
one)
  mappend :: DynQuantity a -> DynQuantity a -> DynQuantity a
mappend = DynQuantity a -> DynQuantity a -> DynQuantity a
forall a. Semigroup a => a -> a -> a
(Data.Semigroup.<>)

-- | A 'DynQuantity' which does not correspond to a value of any dimension.
invalidQuantity :: DynQuantity a
invalidQuantity :: DynQuantity a
invalidQuantity = DynamicDimension -> a -> DynQuantity a
forall a. DynamicDimension -> a -> DynQuantity a
DynQuantity DynamicDimension
NoDimension (a -> DynQuantity a) -> a -> DynQuantity a
forall a b. (a -> b) -> a -> b
$ String -> a
forall a. HasCallStack => String -> a
error String
"Attempt to evaluate the value of an invalid quantity."

-- | A 'DynQuantity' which corresponds to zero value of any dimension.
--
-- When combined through arithmetic with other 'DynQuantity's, inference is performed. For example,
-- adding a length to polydimensional zero produces that length. Adding two polydimensional zeros produces another.
-- Taking the sine of a polydimensional zero interprets it as a dimensionless zero and produces a dimensionless result.
--
-- Note that division by 'polydimensionalZero' produces a polydimensional result, which may be an error or some representation
-- of infinity, as determined by the underlying arithmetic type. This behavior was chosen for consistency with the behavior of division
-- by zero 'DynQuantity's of a specific dimension.
polydimensionalZero :: (Num a) => DynQuantity a
polydimensionalZero :: DynQuantity a
polydimensionalZero = DynamicDimension -> a -> DynQuantity a
forall a. DynamicDimension -> a -> DynQuantity a
DynQuantity DynamicDimension
AnyDimension a
0

-- Lifts a function which is only valid on dimensionless quantities into a function on DynQuantitys.
liftDimensionless :: (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless :: (a -> a) -> DynQuantity a -> DynQuantity a
liftDimensionless = (DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
forall a.
(DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
liftDQ (DynamicDimension -> DynamicDimension -> DynamicDimension
matchDimensions (DynamicDimension -> DynamicDimension -> DynamicDimension)
-> DynamicDimension -> DynamicDimension -> DynamicDimension
forall a b. (a -> b) -> a -> b
$ Dimension' -> DynamicDimension
SomeDimension Dimension'
D.dOne)

-- Lifts a function on values into a function on DynQuantitys.
liftDQ :: (DynamicDimension -> DynamicDimension) -- ^ How the function operates on dimensions.
       -> (a -> a) -- ^ How the function operates on values.
       -> DynQuantity a -> DynQuantity a
liftDQ :: (DynamicDimension -> DynamicDimension)
-> (a -> a) -> DynQuantity a -> DynQuantity a
liftDQ DynamicDimension -> DynamicDimension
fd a -> a
fv (DynQuantity DynamicDimension
d a
v) = case DynamicDimension -> DynamicDimension
fd DynamicDimension
d of
                                   DynamicDimension
NoDimension -> DynQuantity a
forall a. DynQuantity a
invalidQuantity
                                   DynamicDimension
d' -> DynamicDimension -> a -> DynQuantity a
forall a. DynamicDimension -> a -> DynQuantity a
DynQuantity DynamicDimension
d' (a -> DynQuantity a) -> a -> DynQuantity a
forall a b. (a -> b) -> a -> b
$ a -> a
fv a
v

-- Lifts a function on values into a function on DynQuantitys.
--
-- This works by treating polydimensional zeros as dimensionless zeros. If that is not the desired behavior,
-- handle polydimensional zeros first and then call this function.
liftDQ2 :: (DynamicDimension -> DynamicDimension -> DynamicDimension)
        -> (a -> a -> a)
        -> DynQuantity a -> DynQuantity a -> DynQuantity a
liftDQ2 :: (DynamicDimension -> DynamicDimension -> DynamicDimension)
-> (a -> a -> a) -> DynQuantity a -> DynQuantity a -> DynQuantity a
liftDQ2 DynamicDimension -> DynamicDimension -> DynamicDimension
fd a -> a -> a
fv (DynQuantity DynamicDimension
d1 a
v1) (DynQuantity DynamicDimension
d2 a
v2) = case DynamicDimension -> DynamicDimension -> DynamicDimension
fd DynamicDimension
d1 DynamicDimension
d2 of
                                                          DynamicDimension
NoDimension -> DynQuantity a
forall a. DynQuantity a
invalidQuantity
                                                          DynamicDimension
d' -> DynamicDimension -> a -> DynQuantity a
forall a. DynamicDimension -> a -> DynQuantity a
DynQuantity DynamicDimension
d' (a -> DynQuantity a) -> a -> DynQuantity a
forall a b. (a -> b) -> a -> b
$ a -> a -> a
fv a
v1 a
v2

-- Transforms a dynamic dimension in a way which is always valid
valid :: (Dimension' -> Dimension') -> DynamicDimension -> DynamicDimension
valid :: (Dimension' -> Dimension') -> DynamicDimension -> DynamicDimension
valid Dimension' -> Dimension'
_ DynamicDimension
AnyDimension      = DynamicDimension
AnyDimension
valid Dimension' -> Dimension'
f (SomeDimension Dimension'
d) = Dimension' -> DynamicDimension
SomeDimension (Dimension' -> Dimension'
f Dimension'
d)
valid Dimension' -> Dimension'
_ DynamicDimension
NoDimension       = DynamicDimension
NoDimension

whenValid :: (Dimension' -> Maybe Dimension') -> DynamicDimension -> DynamicDimension
whenValid :: (Dimension' -> Maybe Dimension')
-> DynamicDimension -> DynamicDimension
whenValid Dimension' -> Maybe Dimension'
_ DynamicDimension
AnyDimension = DynamicDimension
AnyDimension
whenValid Dimension' -> Maybe Dimension'
f (SomeDimension Dimension'
d) | Just Dimension'
d' <- Dimension' -> Maybe Dimension'
f Dimension'
d = Dimension' -> DynamicDimension
SomeDimension Dimension'
d'
whenValid Dimension' -> Maybe Dimension'
_ DynamicDimension
_ = DynamicDimension
NoDimension

constant :: Dimension' -> DynamicDimension -> DynamicDimension
constant :: Dimension' -> DynamicDimension -> DynamicDimension
constant Dimension'
d DynamicDimension
AnyDimension = Dimension' -> DynamicDimension
SomeDimension Dimension'
d
constant Dimension'
d (SomeDimension Dimension'
_) = Dimension' -> DynamicDimension
SomeDimension Dimension'
d
constant Dimension'
_ DynamicDimension
_ = DynamicDimension
NoDimension

-- Transforms two dynamic dimensions in a way which is always valid
valid2 :: (Dimension' -> Dimension' -> Dimension') -> DynamicDimension -> DynamicDimension -> DynamicDimension
valid2 :: (Dimension' -> Dimension' -> Dimension')
-> DynamicDimension -> DynamicDimension -> DynamicDimension
valid2 Dimension' -> Dimension' -> Dimension'
_ DynamicDimension
AnyDimension       (SomeDimension Dimension'
_)  = DynamicDimension
AnyDimension
valid2 Dimension' -> Dimension' -> Dimension'
_ (SomeDimension Dimension'
_)  DynamicDimension
AnyDimension       = DynamicDimension
AnyDimension
valid2 Dimension' -> Dimension' -> Dimension'
_ DynamicDimension
AnyDimension       DynamicDimension
AnyDimension       = DynamicDimension
AnyDimension
valid2 Dimension' -> Dimension' -> Dimension'
f (SomeDimension Dimension'
d1) (SomeDimension Dimension'
d2) = Dimension' -> DynamicDimension
SomeDimension (Dimension' -> Dimension' -> Dimension'
f Dimension'
d1 Dimension'
d2)
valid2 Dimension' -> Dimension' -> Dimension'
_ DynamicDimension
_                  DynamicDimension
_                  = DynamicDimension
NoDimension

matchDimensions3 :: DynamicDimension -> DynamicDimension -> DynamicDimension -> DynamicDimension
matchDimensions3 :: DynamicDimension
-> DynamicDimension -> DynamicDimension -> DynamicDimension
matchDimensions3 DynamicDimension
x DynamicDimension
y DynamicDimension
z = DynamicDimension -> DynamicDimension -> DynamicDimension
matchDimensions DynamicDimension
x (DynamicDimension -> DynamicDimension -> DynamicDimension
matchDimensions DynamicDimension
y DynamicDimension
z)

-- | A 'Unit' whose 'Dimension' is only known dynamically.
data AnyUnit = AnyUnit Dimension' (UnitName 'NonMetric) ExactPi
  deriving ((forall x. AnyUnit -> Rep AnyUnit x)
-> (forall x. Rep AnyUnit x -> AnyUnit) -> Generic AnyUnit
forall x. Rep AnyUnit x -> AnyUnit
forall x. AnyUnit -> Rep AnyUnit x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep AnyUnit x -> AnyUnit
$cfrom :: forall x. AnyUnit -> Rep AnyUnit x
Generic, Typeable)

instance Show AnyUnit where
  show :: AnyUnit -> String
show (AnyUnit Dimension'
_ UnitName 'NonMetric
n ExactPi
e) = UnitName 'NonMetric -> String
forall a. Show a => a -> String
show UnitName 'NonMetric
n String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" =def= " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ExactPi -> String
forall a. Show a => a -> String
show ExactPi
e String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" of the SI base unit"

instance HasDynamicDimension AnyUnit where

instance HasDimension AnyUnit where
  dimension :: AnyUnit -> Dimension'
dimension (AnyUnit Dimension'
d UnitName 'NonMetric
_ ExactPi
_) = Dimension'
d

instance I.HasInterchangeName AnyUnit where
  interchangeName :: AnyUnit -> InterchangeName
interchangeName (AnyUnit Dimension'
_ UnitName 'NonMetric
n ExactPi
_) = UnitName 'NonMetric -> InterchangeName
forall a. HasInterchangeName a => a -> InterchangeName
I.interchangeName UnitName 'NonMetric
n

-- | 'AnyUnit's form a 'Semigroup' under multiplication.
instance Semigroup AnyUnit where
  <> :: AnyUnit -> AnyUnit -> AnyUnit
(<>) = AnyUnit -> AnyUnit -> AnyUnit
(Numeric.Units.Dimensional.Dynamic.*)

-- | 'AnyUnit's form a 'Monoid' under multiplication.
instance Monoid AnyUnit where
  mempty :: AnyUnit
mempty = Unit 'NonMetric DOne ExactPi -> AnyUnit
forall (d :: Dimension) (m :: Metricality).
KnownDimension d =>
Unit m d ExactPi -> AnyUnit
demoteUnit' Unit 'NonMetric DOne ExactPi
forall a. Num a => Unit 'NonMetric DOne a
one
  mappend :: AnyUnit -> AnyUnit -> AnyUnit
mappend = AnyUnit -> AnyUnit -> AnyUnit
forall a. Semigroup a => a -> a -> a
(Data.Semigroup.<>)

anyUnitName :: AnyUnit -> UnitName 'NonMetric
anyUnitName :: AnyUnit -> UnitName 'NonMetric
anyUnitName (AnyUnit Dimension'
_ UnitName 'NonMetric
n ExactPi
_) = UnitName 'NonMetric
n

-- | The dynamic SI coherent unit of a given dimension.
siUnit :: Dimension' -> AnyUnit
siUnit :: Dimension' -> AnyUnit
siUnit Dimension'
d = Dimension' -> UnitName 'NonMetric -> ExactPi -> AnyUnit
AnyUnit Dimension'
d (Dimension' -> UnitName 'NonMetric
baseUnitName Dimension'
d) ExactPi
1

-- | Converts a 'Unit' of statically known 'Dimension' into an 'AnyUnit'.
demoteUnit :: forall m d a.(KnownDimension d) => Unit m d a -> AnyUnit
demoteUnit :: Unit m d a -> AnyUnit
demoteUnit Unit m d a
u = Dimension' -> UnitName 'NonMetric -> ExactPi -> AnyUnit
AnyUnit Dimension'
dim (Unit 'NonMetric d a -> UnitName 'NonMetric
forall (m :: Metricality) (d :: Dimension) a.
Unit m d a -> UnitName m
name (Unit 'NonMetric d a -> UnitName 'NonMetric)
-> Unit 'NonMetric d a -> UnitName 'NonMetric
forall a b. (a -> b) -> a -> b
$ Unit m d a -> Unit 'NonMetric d a
forall (m :: Metricality) (d :: Dimension) a.
Unit m d a -> Unit 'NonMetric d a
weaken Unit m d a
u) (Unit m d a -> ExactPi
forall (m :: Metricality) (d :: Dimension) a. Unit m d a -> ExactPi
exactValue Unit m d a
u)
  where
    dim :: Dimension'
dim = Proxy d -> Dimension'
forall a. HasDimension a => a -> Dimension'
dimension (Proxy d
forall k (t :: k). Proxy t
Proxy :: Proxy d)

-- | Converts a 'Unit' of statically known 'Dimension' into an 'AnyUnit'.
--
-- This is the same as the more general 'demoteUnit' but is useful in certain circumstances to avoid
-- needlessly introducing an ambiguous type variable.
demoteUnit' :: (KnownDimension d) => Unit m d ExactPi -> AnyUnit
demoteUnit' :: Unit m d ExactPi -> AnyUnit
demoteUnit' = Unit m d ExactPi -> AnyUnit
forall (m :: Metricality) (d :: Dimension) a.
KnownDimension d =>
Unit m d a -> AnyUnit
demoteUnit

-- | Converts an 'AnyUnit' into a 'Unit' of statically known 'Dimension', or 'Nothing' if the dimension does not match.
--
-- The result is represented in 'ExactPi', conversion to other representations is possible using 'changeRepApproximate'.
--
-- The result is always tagged as 'NonMetric', conversion to a 'Metric' unit can be attempted using 'strengthen'.
promoteUnit :: forall d.(KnownDimension d) => AnyUnit -> Maybe (Unit 'NonMetric d ExactPi)
promoteUnit :: AnyUnit -> Maybe (Unit 'NonMetric d ExactPi)
promoteUnit (AnyUnit Dimension'
dim UnitName 'NonMetric
n ExactPi
e) | Dimension'
dim Dimension' -> Dimension' -> Bool
forall a. Eq a => a -> a -> Bool
== Dimension'
dim' = Unit 'NonMetric d ExactPi -> Maybe (Unit 'NonMetric d ExactPi)
forall a. a -> Maybe a
Just (Unit 'NonMetric d ExactPi -> Maybe (Unit 'NonMetric d ExactPi))
-> Unit 'NonMetric d ExactPi -> Maybe (Unit 'NonMetric d ExactPi)
forall a b. (a -> b) -> a -> b
$ UnitName 'NonMetric
-> ExactPi
-> Unit 'NonMetric d ExactPi
-> Unit 'NonMetric d ExactPi
forall a (m :: Metricality) (m1 :: Metricality) (d :: Dimension).
Floating a =>
UnitName m -> ExactPi -> Unit m1 d a -> Unit m d a
mkUnitR UnitName 'NonMetric
n ExactPi
e Unit 'NonMetric d ExactPi
forall (d :: Dimension) a.
(KnownDimension d, Num a) =>
Unit 'NonMetric d a
Dim.siUnit
                              | Bool
otherwise   = Maybe (Unit 'NonMetric d ExactPi)
forall a. Maybe a
Nothing
  where
    dim' :: Dimension'
dim' = Proxy d -> Dimension'
forall a. HasDimension a => a -> Dimension'
dimension (Proxy d
forall k (t :: k). Proxy t
Proxy :: Proxy d)

-- | Forms the reciprocal of a dynamic unit.
recip :: AnyUnit -> AnyUnit
recip :: AnyUnit -> AnyUnit
recip (AnyUnit Dimension'
d UnitName 'NonMetric
n ExactPi
e) = Dimension' -> UnitName 'NonMetric -> ExactPi -> AnyUnit
AnyUnit (Dimension' -> Dimension'
D.recip Dimension'
d) (UnitName 'NonMetric
N.nOne UnitName 'NonMetric -> UnitName 'NonMetric -> UnitName 'NonMetric
forall (m1 :: Metricality) (m2 :: Metricality).
UnitName m1 -> UnitName m2 -> UnitName 'NonMetric
N./ UnitName 'NonMetric
n) (ExactPi -> ExactPi
forall a. Fractional a => a -> a
P.recip ExactPi
e)

-- | Forms the product of two dynamic units.
(*) :: AnyUnit -> AnyUnit -> AnyUnit
(AnyUnit Dimension'
d1 UnitName 'NonMetric
n1 ExactPi
e1) * :: AnyUnit -> AnyUnit -> AnyUnit
* (AnyUnit Dimension'
d2 UnitName 'NonMetric
n2 ExactPi
e2) = Dimension' -> UnitName 'NonMetric -> ExactPi -> AnyUnit
AnyUnit (Dimension'
d1 Dimension' -> Dimension' -> Dimension'
D.* Dimension'
d2) (UnitName 'NonMetric
n1 UnitName 'NonMetric -> UnitName 'NonMetric -> UnitName 'NonMetric
forall (m1 :: Metricality) (m2 :: Metricality).
UnitName m1 -> UnitName m2 -> UnitName 'NonMetric
N.* UnitName 'NonMetric
n2) (ExactPi
e1 ExactPi -> ExactPi -> ExactPi
forall a. Num a => a -> a -> a
P.* ExactPi
e2)

-- | Forms the quotient of two dynamic units.
(/) :: AnyUnit -> AnyUnit -> AnyUnit
(AnyUnit Dimension'
d1 UnitName 'NonMetric
n1 ExactPi
e1) / :: AnyUnit -> AnyUnit -> AnyUnit
/ (AnyUnit Dimension'
d2 UnitName 'NonMetric
n2 ExactPi
e2) = Dimension' -> UnitName 'NonMetric -> ExactPi -> AnyUnit
AnyUnit (Dimension'
d1 Dimension' -> Dimension' -> Dimension'
D./ Dimension'
d2) (UnitName 'NonMetric
n1 UnitName 'NonMetric -> UnitName 'NonMetric -> UnitName 'NonMetric
forall (m1 :: Metricality) (m2 :: Metricality).
UnitName m1 -> UnitName m2 -> UnitName 'NonMetric
N./ UnitName 'NonMetric
n2) (ExactPi
e1 ExactPi -> ExactPi -> ExactPi
forall a. Fractional a => a -> a -> a
P./ ExactPi
e2)

-- | Raises a dynamic unit to an integer power.
(^) :: (P.Integral a) => AnyUnit -> a -> AnyUnit
(AnyUnit Dimension'
d UnitName 'NonMetric
n ExactPi
e) ^ :: AnyUnit -> a -> AnyUnit
^ a
x = Dimension' -> UnitName 'NonMetric -> ExactPi -> AnyUnit
AnyUnit (Dimension'
d Dimension' -> Int -> Dimension'
D.^ a -> Int
forall a b. (Integral a, Num b) => a -> b
P.fromIntegral a
x) (UnitName 'NonMetric
n UnitName 'NonMetric -> Int -> UnitName 'NonMetric
forall (m :: Metricality). UnitName m -> Int -> UnitName 'NonMetric
N.^ a -> Int
forall a b. (Integral a, Num b) => a -> b
P.fromIntegral a
x) (ExactPi
e ExactPi -> a -> ExactPi
forall a b. (Fractional a, Integral b) => a -> b -> a
P.^^ a
x)

-- | Applies a prefix to a dynamic unit.
-- Returns 'Nothing' if the 'Unit' was 'NonMetric' and thus could not accept a prefix.
applyPrefix :: N.Prefix -> AnyUnit -> Maybe AnyUnit
applyPrefix :: Prefix -> AnyUnit -> Maybe AnyUnit
applyPrefix Prefix
p (AnyUnit Dimension'
d UnitName 'NonMetric
n ExactPi
e) = do
                                  UnitName 'Metric
n' <- UnitName 'NonMetric -> Maybe (UnitName 'Metric)
forall (m :: Metricality). UnitName m -> Maybe (UnitName 'Metric)
N.strengthen UnitName 'NonMetric
n
                                  let n'' :: UnitName 'NonMetric
n'' = Prefix -> UnitName 'Metric -> UnitName 'NonMetric
N.applyPrefix Prefix
p UnitName 'Metric
n'
                                  let e' :: ExactPi
e' = (Rational -> ExactPi
forall a. Fractional a => Rational -> a
P.fromRational (Rational -> ExactPi) -> Rational -> ExactPi
forall a b. (a -> b) -> a -> b
$ Prefix -> Rational
N.scaleFactor Prefix
p) ExactPi -> ExactPi -> ExactPi
forall a. Num a => a -> a -> a
P.* ExactPi
e
                                  AnyUnit -> Maybe AnyUnit
forall (m :: Type -> Type) a. Monad m => a -> m a
return (AnyUnit -> Maybe AnyUnit) -> AnyUnit -> Maybe AnyUnit
forall a b. (a -> b) -> a -> b
$ Dimension' -> UnitName 'NonMetric -> ExactPi -> AnyUnit
AnyUnit Dimension'
d UnitName 'NonMetric
n'' ExactPi
e'

-- | Forms a dynamic quantity by multipliying a number and a dynamic unit.
(*~) :: (Floating a, Promotable q) => a -> AnyUnit -> q a
a
x *~ :: a -> AnyUnit -> q a
*~ (AnyUnit Dimension'
d UnitName 'NonMetric
_ ExactPi
e) = AnyQuantity a -> q a
forall (q :: Type -> Type) a. Promotable q => AnyQuantity a -> q a
promotableIn (AnyQuantity a -> q a) -> AnyQuantity a -> q a
forall a b. (a -> b) -> a -> b
$ Dimension' -> a -> AnyQuantity a
forall a. Dimension' -> a -> AnyQuantity a
AnyQuantity Dimension'
d (a
x a -> a -> a
forall a. Num a => a -> a -> a
P.* ExactPi -> a
forall a. Floating a => ExactPi -> a
approximateValue ExactPi
e)

-- | Divides a dynamic quantity by a dynamic unit, obtaining the numerical value of the quantity
-- expressed in that unit if they are of the same physical dimension, or 'Nothing' otherwise.
(/~) :: (Floating a, Promotable q) => q a -> AnyUnit -> Maybe a
q a
x /~ :: q a -> AnyUnit -> Maybe a
/~ (AnyUnit Dimension'
d UnitName 'NonMetric
_ ExactPi
e) = case q a -> DynQuantity a
forall (q :: Type -> Type) a. Promotable q => q a -> DynQuantity a
promotableOut q a
x of
                         DynQuantity DynamicDimension
d' a
x' | DynamicDimension
d' DynamicDimension -> Dimension' -> Bool
forall a. HasDynamicDimension a => a -> Dimension' -> Bool
`isCompatibleWith` Dimension'
d -> a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ a
x' a -> a -> a
forall a. Fractional a => a -> a -> a
P./ ExactPi -> a
forall a. Floating a => ExactPi -> a
approximateValue ExactPi
e
                                           | Bool
otherwise -> Maybe a
forall a. Maybe a
Nothing