{-# LANGUAGE TypeOperators, FlexibleContexts, DataKinds, TypeFamilies,
             ScopedTypeVariables, ConstraintKinds, GeneralizedNewtypeDeriving,
             MultiParamTypeClasses, FlexibleInstances, InstanceSigs, CPP #-}

#if __GLASGOW_HASKELL__ >= 711
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
#endif

-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Metrology.Linear
-- Copyright   :  (C) 2014 Richard Eisenberg, (C) 2015 Tobias Markus
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  Richard Eisenberg (rae@cs.brynmawr.edu)
-- Stability   :  experimental
-- Portability :  non-portable
--
-- Exports combinators for building quantities out of vectors, from the
-- @linear@ library.
------------------------------------------------------------------------------

module Data.Metrology.Linear (
  -- * Term-level combinators

  -- | The term-level arithmetic operators are defined by
  -- applying vertical bar(s) to the sides the dimensioned
  -- quantities acts on.

  -- ** Additive operations
  zeroV, (|^+^|), (|^-^|), qNegateV, qSumV,

  -- ** Multiplicative operations
  (|*^|), (|^*|), (|^/|), (*^|), (|^*), (|^/), (|.|),

  -- ** Vector-space operations
  qBasis, qBasisFor, qScaled, qOuter, qUnit,
  qQuadrance, qNorm, qSignorm, qProject, qCross,

  -- ** Affine operations
  (|.-.|), (|.+^|), (|.-^|), qQd, qDistance, qQdA, qDistanceA,

  -- * Nondimensional units, conversion between quantities and numeric values
  numInV, (^#), quOfV, (^%), showInV,
  convertV, constantV,

  ) where

import Data.Metrology.Qu
import Data.Metrology.LCSU
import Data.Metrology.Validity
import Data.Metrology.Factor
import Data.Metrology.Z as Z
import Data.Metrology.Units

import Linear
import Linear.Affine hiding (P)
import qualified Control.Lens as Lens

import Data.Proxy
import Data.Foldable    as F
#if __GLASGOW_HASKELL__ < 709
import Data.Traversable ( Traversable )
#endif

---------------------------------------
-- Additive operations
---------------------------------------

-- | The number 0, polymorphic in its dimension. Use of this will
-- often require a type annotation.
zeroV :: (Additive f, Num a) => Qu d l (f a)
zeroV :: Qu d l (f a)
zeroV = f a -> Qu d l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu f a
forall (f :: * -> *) a. (Additive f, Num a) => f a
Linear.zero

infixl 6 |^+^|
-- | Add two compatible vector quantities
(|^+^|) :: (d1 @~ d2, Additive f, Num a)
        => Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l (f a)
(Qu f a
a) |^+^| :: Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l (f a)
|^+^| (Qu f a
b) = f a -> Qu d1 l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> f a -> f a
forall (f :: * -> *) a. (Additive f, Num a) => f a -> f a -> f a
^+^ f a
b)

-- | Negate a vector quantity
qNegateV :: (Additive f, Num a) => Qu d l (f a) -> Qu d l (f a)
qNegateV :: Qu d l (f a) -> Qu d l (f a)
qNegateV (Qu f a
x) = f a -> Qu d l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a -> f a
forall (f :: * -> *) a. (Functor f, Num a) => f a -> f a
negated f a
x)

infixl 6 |^-^|
-- | Subtract two compatible quantities
(|^-^|) :: (d1 @~ d2, Additive f, Num a)
        => Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l (f a)
(Qu f a
a) |^-^| :: Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l (f a)
|^-^| (Qu f a
b) = f a -> Qu d1 l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> f a -> f a
forall (f :: * -> *) a. (Additive f, Num a) => f a -> f a -> f a
^-^ f a
b)

-- | Take the sum of a list of quantities
qSumV :: (Foldable t, Additive f, Num a) => t (Qu d l (f a)) -> Qu d l (f a)
qSumV :: t (Qu d l (f a)) -> Qu d l (f a)
qSumV = (Qu d l (f a) -> Qu d l (f a) -> Qu d l (f a))
-> Qu d l (f a) -> t (Qu d l (f a)) -> Qu d l (f a)
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr Qu d l (f a) -> Qu d l (f a) -> Qu d l (f a)
forall (d1 :: [Factor *]) (d2 :: [Factor *]) (f :: * -> *) a
       (l :: LCSU *).
(d1 @~ d2, Additive f, Num a) =>
Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l (f a)
(|^+^|) Qu d l (f a)
forall (f :: * -> *) a (d :: [Factor *]) (l :: LCSU *).
(Additive f, Num a) =>
Qu d l (f a)
zeroV

---------------------------------------
-- Multiplicative operations
---------------------------------------

infixl 7 |*^|, |^*|, |^/|
-- | Multiply a scalar quantity by a vector quantity
(|*^|) :: (Functor f, Num a)
       => Qu d1 l a -> Qu d2 l (f a) -> Qu (Normalize (d1 @+ d2)) l (f a)
(Qu a
a) |*^| :: Qu d1 l a -> Qu d2 l (f a) -> Qu (Normalize (d1 @+ d2)) l (f a)
|*^| (Qu f a
b) = f a -> Qu (Normalize (d1 @@+ Reorder d2 d1)) l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (a
a a -> f a -> f a
forall (f :: * -> *) a. (Functor f, Num a) => a -> f a -> f a
*^ f a
b)

-- | Multiply a vector quantity by a scalar quantity
(|^*|) :: (Functor f, Num a)
       => Qu d1 l (f a) -> Qu d2 l a -> Qu (Normalize (d1 @+ d2)) l (f a)
(Qu f a
a) |^*| :: Qu d1 l (f a) -> Qu d2 l a -> Qu (Normalize (d1 @+ d2)) l (f a)
|^*| (Qu a
b) = f a -> Qu (Normalize (d1 @@+ Reorder d2 d1)) l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> a -> f a
forall (f :: * -> *) a. (Functor f, Num a) => f a -> a -> f a
^* a
b)

-- | Divide a vector quantity by a scalar quantity
(|^/|) :: (Functor f, Fractional a)
       => Qu d1 l (f a) -> Qu d2 l a -> Qu (Normalize (d1 @- d2)) l (f a)
(Qu f a
a) |^/| :: Qu d1 l (f a) -> Qu d2 l a -> Qu (Normalize (d1 @- d2)) l (f a)
|^/| (Qu a
b) = f a -> Qu (Normalize (d1 @- d2)) l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> a -> f a
forall (f :: * -> *) a.
(Functor f, Fractional a) =>
f a -> a -> f a
^/ a
b)

infixl 7 |^/
-- | Divide a quantity by a plain old number
(|^/) :: (Functor f, Fractional a) => Qu d l (f a) -> a -> Qu d l (f a)
(Qu f a
a) |^/ :: Qu d l (f a) -> a -> Qu d l (f a)
|^/ a
b = f a -> Qu d l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> a -> f a
forall (f :: * -> *) a.
(Functor f, Fractional a) =>
f a -> a -> f a
^/ a
b)

infixl 7 *^| , |^*
-- | Multiply a quantity by a plain old number from the left
(*^|) :: (Functor f, Num a) => a -> Qu b l (f a) -> Qu b l (f a)
a
a *^| :: a -> Qu b l (f a) -> Qu b l (f a)
*^| (Qu f a
b) =  f a -> Qu b l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (a
a a -> f a -> f a
forall (f :: * -> *) a. (Functor f, Num a) => a -> f a -> f a
*^ f a
b)

-- | Multiply a quantity by a plain old number from the right
(|^*) :: (Functor f, Num a) => Qu b l (f a) -> a -> Qu b l (f a)
(Qu f a
a) |^* :: Qu b l (f a) -> a -> Qu b l (f a)
|^* a
b = f a -> Qu b l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> a -> f a
forall (f :: * -> *) a. (Functor f, Num a) => f a -> a -> f a
^* a
b)

---------------------------------------
-- Vector-space operations
---------------------------------------

-- | Return a default basis, where each basis element measures 1 of the
-- unit provided.
qBasis :: ( ValidDLU dim lcsu unit
          , Additive f
          , Traversable f
          , Fractional a )
       => unit -> [Qu dim lcsu (f a)]
qBasis :: unit -> [Qu dim lcsu (f a)]
qBasis unit
u = (f a -> Qu dim lcsu (f a)) -> [f a] -> [Qu dim lcsu (f a)]
forall a b. (a -> b) -> [a] -> [b]
map (f a -> unit -> Qu dim lcsu (f a)
forall (dim :: [Factor *]) (lcsu :: LCSU *) unit (f :: * -> *) a.
(ValidDLU dim lcsu unit, Functor f, Fractional a) =>
f a -> unit -> Qu dim lcsu (f a)
^% unit
u) [f a]
forall (t :: * -> *) a. (Additive t, Traversable t, Num a) => [t a]
basis

-- | Return a default basis for the vector space provided. Each basis
-- element measures 1 of the unit provided.
qBasisFor :: ( ValidDLU dim lcsu unit
             , Additive f
             , Traversable f
             , Fractional a )
          => unit -> Qu dim lcsu (f b) -> [Qu dim lcsu (f a)]
qBasisFor :: unit -> Qu dim lcsu (f b) -> [Qu dim lcsu (f a)]
qBasisFor unit
u (Qu f b
vec) = (f a -> Qu dim lcsu (f a)) -> [f a] -> [Qu dim lcsu (f a)]
forall a b. (a -> b) -> [a] -> [b]
map (f a -> unit -> Qu dim lcsu (f a)
forall (dim :: [Factor *]) (lcsu :: LCSU *) unit (f :: * -> *) a.
(ValidDLU dim lcsu unit, Functor f, Fractional a) =>
f a -> unit -> Qu dim lcsu (f a)
^% unit
u) (f b -> [f a]
forall (t :: * -> *) a b. (Traversable t, Num a) => t b -> [t a]
basisFor f b
vec)

-- | Produce a diagonal (scale) matrix from a vector
qScaled :: (Traversable f, Num a)
        => Qu dim lcsu (f a) -> Qu dim lcsu (f (f a))
qScaled :: Qu dim lcsu (f a) -> Qu dim lcsu (f (f a))
qScaled (Qu f a
vec) = f (f a) -> Qu dim lcsu (f (f a))
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a -> f (f a)
forall (t :: * -> *) a. (Traversable t, Num a) => t a -> t (t a)
scaled f a
vec)

-- | Outer (tensor) product of two quantity vectors
qOuter :: (Functor f, Functor g, Num a)
       => Qu d1 l (f a) -> Qu d2 l (g a) -> Qu (Normalize (d1 @+ d2)) l (f (g a))
qOuter :: Qu d1 l (f a)
-> Qu d2 l (g a) -> Qu (Normalize (d1 @+ d2)) l (f (g a))
qOuter (Qu f a
a) (Qu g a
b) = f (g a) -> Qu (Normalize (d1 @@+ Reorder d2 d1)) l (f (g a))
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> g a -> f (g a)
forall (f :: * -> *) (g :: * -> *) a.
(Functor f, Functor g, Num a) =>
f a -> g a -> f (g a)
`outer` g a
b)

-- | Create a unit vector from a setter and a choice of unit.
qUnit :: (ValidDLU dim lcsu unit, Additive t, Fractional a)
      => Lens.ASetter' (t a) a -> unit -> Qu dim lcsu (t a)
qUnit :: ASetter' (t a) a -> unit -> Qu dim lcsu (t a)
qUnit ASetter' (t a) a
setter unit
u = ASetter' (t a) a -> t a
forall (t :: * -> *) a.
(Additive t, Num a) =>
ASetter' (t a) a -> t a
unit ASetter' (t a) a
setter t a -> unit -> Qu dim lcsu (t a)
forall (dim :: [Factor *]) (lcsu :: LCSU *) unit (f :: * -> *) a.
(ValidDLU dim lcsu unit, Functor f, Fractional a) =>
f a -> unit -> Qu dim lcsu (f a)
^% unit
u

infixl 7 |.|
-- | Take a inner (dot) product between two quantities.
(|.|) :: (Metric f, Num a) => Qu d1 l (f a) -> Qu d2 l (f a) -> Qu (Normalize (d1 @+ d2)) l a
(Qu f a
a) |.| :: Qu d1 l (f a) -> Qu d2 l (f a) -> Qu (Normalize (d1 @+ d2)) l a
|.| (Qu f a
b) = a -> Qu (Normalize (d1 @@+ Reorder d2 d1)) l a
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> f a -> a
forall (f :: * -> *) a. (Metric f, Num a) => f a -> f a -> a
`dot` f a
b)

-- | Square the length of a vector.
qQuadrance :: (Metric f, Num a) => Qu d l (f a) -> Qu (d @* Z.Two) l a
qQuadrance :: Qu d l (f a) -> Qu (d @* Two) l a
qQuadrance (Qu f a
x) = a -> Qu (d @* Two) l a
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a -> a
forall (f :: * -> *) a. (Metric f, Num a) => f a -> a
quadrance f a
x)

-- | Length of a vector.
qNorm :: (Metric f, Floating a) => Qu d l (f a) -> Qu d l a
qNorm :: Qu d l (f a) -> Qu d l a
qNorm (Qu f a
x) = a -> Qu d l a
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a -> a
forall (f :: * -> *) a. (Metric f, Floating a) => f a -> a
norm f a
x)

-- | Vector in same direction as given one but with length of one. If given the zero
-- vector, then return it. The returned vector is dimensionless.
qSignorm :: (Metric f, Floating a)
         => Qu d l (f a) -> Qu '[] l (f a)
qSignorm :: Qu d l (f a) -> Qu '[] l (f a)
qSignorm (Qu f a
x) = f a -> Qu '[] l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a -> f a
forall (f :: * -> *) a. (Metric f, Floating a) => f a -> f a
signorm f a
x)

-- | @qProject u v@ computes the projection of @v@ onto @u@.
qProject :: (Metric f, Fractional a)
         => Qu d2 l (f a) -> Qu d1 l (f a) -> Qu d1 l (f a)
qProject :: Qu d2 l (f a) -> Qu d1 l (f a) -> Qu d1 l (f a)
qProject (Qu f a
u) (Qu f a
v) = f a -> Qu d1 l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
u f a -> f a -> f a
forall (v :: * -> *) a.
(Metric v, Fractional a) =>
v a -> v a -> v a
`project` f a
v)

-- | Cross product of 3D vectors.
qCross :: Num a
       => Qu d1 l (V3 a) -> Qu d2 l (V3 a) -> Qu (Normalize (d1 @+ d2)) l (V3 a)
qCross :: Qu d1 l (V3 a)
-> Qu d2 l (V3 a) -> Qu (Normalize (d1 @+ d2)) l (V3 a)
qCross (Qu V3 a
x) (Qu V3 a
y) = V3 a -> Qu (Normalize (d1 @@+ Reorder d2 d1)) l (V3 a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (V3 a
x V3 a -> V3 a -> V3 a
forall a. Num a => V3 a -> V3 a -> V3 a
`cross` V3 a
y)

-- | Square of the distance between two vectors.
qQd :: (d1 @~ d2, Metric f, Metric (Diff f), Num a)
            => Qu d1 l (f a) -> Qu d2 l (f a) -> Qu (d1 @* Z.Two) l a
qQd :: Qu d1 l (f a) -> Qu d2 l (f a) -> Qu (d1 @* Two) l a
qQd (Qu f a
a) (Qu f a
b) = a -> Qu (d1 @* Two) l a
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> f a -> a
forall (f :: * -> *) a. (Metric f, Num a) => f a -> f a -> a
`qd` f a
b)

-- | Distance between two vectors.
qDistance :: (d1 @~ d2, Metric f, Metric (Diff f), Floating a)
          => Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l a
qDistance :: Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l a
qDistance (Qu f a
a) (Qu f a
b) = a -> Qu d1 l a
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> f a -> a
forall (f :: * -> *) a. (Metric f, Floating a) => f a -> f a -> a
`distance` f a
b)

---------------------------------------
-- Affine space operations
---------------------------------------

-- | Subtract point quantities.
(|.-.|) :: (d1 @~ d2, Affine f, Num a) => Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l (Diff f a)
(Qu f a
a) |.-.| :: Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l (Diff f a)
|.-.| (Qu f a
b) = Diff f a -> Qu d1 l (Diff f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> f a -> Diff f a
forall (p :: * -> *) a. (Affine p, Num a) => p a -> p a -> Diff p a
.-. f a
b)

-- | Add a point to a vector.
(|.+^|) :: (d1 @~ d2, Affine f, Num a) => Qu d1 l (f a) -> Qu d2 l (Diff f a) -> Qu d1 l (f a)
(Qu f a
a) |.+^| :: Qu d1 l (f a) -> Qu d2 l (Diff f a) -> Qu d1 l (f a)
|.+^| (Qu Diff f a
b) = f a -> Qu d1 l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> Diff f a -> f a
forall (p :: * -> *) a. (Affine p, Num a) => p a -> Diff p a -> p a
.+^ Diff f a
b)

-- | Subract a vector from a point.
(|.-^|) :: (d1 @~ d2, Affine f, Num a) => Qu d1 l (f a) -> Qu d2 l (Diff f a) -> Qu d1 l (f a)
(Qu f a
a) |.-^| :: Qu d1 l (f a) -> Qu d2 l (Diff f a) -> Qu d1 l (f a)
|.-^| (Qu Diff f a
b) = f a -> Qu d1 l (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> Diff f a -> f a
forall (p :: * -> *) a. (Affine p, Num a) => p a -> Diff p a -> p a
.-^ Diff f a
b)

-- | Square of the distance between two points.
qQdA :: (d1 @~ d2, Affine f, Foldable (Diff f), Num a)
            => Qu d1 l (f a) -> Qu d2 l (f a) -> Qu (d1 @* Z.Two) l a
qQdA :: Qu d1 l (f a) -> Qu d2 l (f a) -> Qu (d1 @* Two) l a
qQdA (Qu f a
a) (Qu f a
b) = a -> Qu (d1 @* Two) l a
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> f a -> a
forall (p :: * -> *) a.
(Affine p, Foldable (Diff p), Num a) =>
p a -> p a -> a
`qdA` f a
b)

-- | Distance between two points.
qDistanceA :: (d1 @~ d2, Affine f, Foldable (Diff f), Floating a)
          => Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l a
qDistanceA :: Qu d1 l (f a) -> Qu d2 l (f a) -> Qu d1 l a
qDistanceA (Qu f a
a) (Qu f a
b) = a -> Qu d1 l a
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
a f a -> f a -> a
forall a (p :: * -> *).
(Floating a, Foldable (Diff p), Affine p) =>
p a -> p a -> a
`distanceA` f a
b)

---------------------------------------
-- Top-level operations
---------------------------------------

-- | Extracts a numerical value from a dimensioned quantity, expressed in
--   the given unit. For example:
--
--   > inMeters :: Length -> Double
--   > inMeters x = numIn x Meter
--
--   or
--
--   > inMeters x = x # Meter
numInV :: forall unit dim lcsu f a.
         ( ValidDLU dim lcsu unit
         , Functor f
         , Fractional a )
      => Qu dim lcsu (f a) -> unit -> (f a)
numInV :: Qu dim lcsu (f a) -> unit -> f a
numInV (Qu f a
val) unit
u
  = f a
val f a -> a -> f a
forall (f :: * -> *) a. (Functor f, Num a) => f a -> a -> f a
^* Rational -> a
forall a. Fractional a => Rational -> a
fromRational
             (Proxy (LookupList dim lcsu) -> Rational
forall (units :: [Factor *]).
UnitFactor units =>
Proxy units -> Rational
canonicalConvRatioSpec (Proxy (LookupList dim lcsu)
forall k (t :: k). Proxy t
Proxy :: Proxy (LookupList dim lcsu))
              Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ unit -> Rational
forall unit. Unit unit => unit -> Rational
canonicalConvRatio unit
u)

infix 5 ^#
-- | Infix synonym for 'numIn'
(^#) :: ( ValidDLU dim lcsu unit
         , Functor f
         , Fractional a )
    => Qu dim lcsu (f a) -> unit -> (f a)
^# :: Qu dim lcsu (f a) -> unit -> f a
(^#) = Qu dim lcsu (f a) -> unit -> f a
forall unit (dim :: [Factor *]) (lcsu :: LCSU *) (f :: * -> *) a.
(ValidDLU dim lcsu unit, Functor f, Fractional a) =>
Qu dim lcsu (f a) -> unit -> f a
numInV

-- | Creates a dimensioned quantity in the given unit. For example:
--
--   > height :: Length
--   > height = quOf 2.0 Meter
--
--   or
--
--   > height = 2.0 % Meter
quOfV :: forall unit dim lcsu f a.
         ( ValidDLU dim lcsu unit
         , Functor f
         , Fractional a )
      => (f a) -> unit -> Qu dim lcsu (f a)
quOfV :: f a -> unit -> Qu dim lcsu (f a)
quOfV f a
d unit
u
  = f a -> Qu dim lcsu (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a
d f a -> a -> f a
forall (f :: * -> *) a. (Functor f, Num a) => f a -> a -> f a
^* Rational -> a
forall a. Fractional a => Rational -> a
fromRational
               (unit -> Rational
forall unit. Unit unit => unit -> Rational
canonicalConvRatio unit
u
                Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Proxy (LookupList dim lcsu) -> Rational
forall (units :: [Factor *]).
UnitFactor units =>
Proxy units -> Rational
canonicalConvRatioSpec (Proxy (LookupList dim lcsu)
forall k (t :: k). Proxy t
Proxy :: Proxy (LookupList dim lcsu))))

infixr 9 ^%
-- | Infix synonym for 'quOf'
(^%) :: ( ValidDLU dim lcsu unit
         , Functor f
         , Fractional a )
    => (f a) -> unit -> Qu dim lcsu (f a)
^% :: f a -> unit -> Qu dim lcsu (f a)
(^%) = f a -> unit -> Qu dim lcsu (f a)
forall unit (dim :: [Factor *]) (lcsu :: LCSU *) (f :: * -> *) a.
(ValidDLU dim lcsu unit, Functor f, Fractional a) =>
f a -> unit -> Qu dim lcsu (f a)
quOfV

-- | Dimension-keeping cast between different CSUs.
convertV :: forall d l1 l2 f a.
  ( ConvertibleLCSUs d l1 l2
  , Functor f
  , Fractional a )
  => Qu d l1 (f a) -> Qu d l2 (f a)
convertV :: Qu d l1 (f a) -> Qu d l2 (f a)
convertV (Qu f a
x) = f a -> Qu d l2 (f a)
forall (a :: [Factor *]) (lcsu :: LCSU *) n. n -> Qu a lcsu n
Qu (f a -> Qu d l2 (f a)) -> f a -> Qu d l2 (f a)
forall a b. (a -> b) -> a -> b
$ f a
x f a -> a -> f a
forall (f :: * -> *) a. (Functor f, Num a) => f a -> a -> f a
^* Rational -> a
forall a. Fractional a => Rational -> a
fromRational (
  Proxy (LookupList d l1) -> Rational
forall (units :: [Factor *]).
UnitFactor units =>
Proxy units -> Rational
canonicalConvRatioSpec (Proxy (LookupList d l1)
forall k (t :: k). Proxy t
Proxy :: Proxy (LookupList d l1))
  Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Proxy (LookupList d l2) -> Rational
forall (units :: [Factor *]).
UnitFactor units =>
Proxy units -> Rational
canonicalConvRatioSpec (Proxy (LookupList d l2)
forall k (t :: k). Proxy t
Proxy :: Proxy (LookupList d l2)))


-- | Compute the argument in the @DefaultLCSU@, and present the result as
-- lcsu-polymorphic dimension-polymorphic value. Named 'constant' because one
-- of its dominant usecase is to inject constant quantities into
-- dimension-polymorphic expressions.
constantV :: ( d @~ e
            , ConvertibleLCSUs e DefaultLCSU l
            , Functor f
            , Fractional a )
         => Qu d DefaultLCSU (f a) -> Qu e l (f a)
constantV :: Qu d 'DefaultLCSU (f a) -> Qu e l (f a)
constantV = Qu e 'DefaultLCSU (f a) -> Qu e l (f a)
forall (d :: [Factor *]) (l1 :: LCSU *) (l2 :: LCSU *)
       (f :: * -> *) a.
(ConvertibleLCSUs d l1 l2, Functor f, Fractional a) =>
Qu d l1 (f a) -> Qu d l2 (f a)
convertV (Qu e 'DefaultLCSU (f a) -> Qu e l (f a))
-> (Qu d 'DefaultLCSU (f a) -> Qu e 'DefaultLCSU (f a))
-> Qu d 'DefaultLCSU (f a)
-> Qu e l (f a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Qu d 'DefaultLCSU (f a) -> Qu e 'DefaultLCSU (f a)
forall (d :: [Factor *]) (e :: [Factor *]) (l :: LCSU *) n.
(d @~ e) =>
Qu d l n -> Qu e l n
redim

infix 1 `showInV`
-- | Show a dimensioned quantity in a given unit. (The default @Show@
-- instance always uses units as specified in the LCSU.)
showInV :: ( ValidDLU dim lcsu unit
          , Functor f
          , Fractional a
          , Show unit
          , Show a
          , Show (f a) )
       => Qu dim lcsu (f a) -> unit -> String
showInV :: Qu dim lcsu (f a) -> unit -> String
showInV Qu dim lcsu (f a)
x unit
u = f a -> String
forall a. Show a => a -> String
show (Qu dim lcsu (f a)
x Qu dim lcsu (f a) -> unit -> f a
forall (dim :: [Factor *]) (lcsu :: LCSU *) unit (f :: * -> *) a.
(ValidDLU dim lcsu unit, Functor f, Fractional a) =>
Qu dim lcsu (f a) -> unit -> f a
^# unit
u) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" " String -> String -> String
forall a. [a] -> [a] -> [a]
++ unit -> String
forall a. Show a => a -> String
show unit
u