{-# OPTIONS_GHC -Wno-missing-methods #-}

{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Units.Simple.Quantity
  ( Quantity (..)
  ) where

import GHC.TypeLits

import Units.Simple.Unit

-- |A numerical quantity with some associated unit.
-- Units are not created directly with this constructor,
-- but through the individual unit functions.
--
-- Examples:
--
-- >>> import Units.Simple
-- >>> meter -- a unitary quantity associated to meters.
-- 1 m
-- >>> 2.5*ampere -- constructing through literal arithmetic
-- 2.5 A
-- >>> candela' 3.14 -- constructing through the unit constructors
-- 3.14 cd
-- >>> :set -XDataKinds
-- >>> 2 :: Quantity (SingleUnit 'Second) Rational
-- 2 % 1 s
--
-- Associated units are represented through a phantom parameter of the 'Units' kind synonym.
-- These are currently implemented as a type-level pair of lists representing the power
-- to which each unit is raised. Units can be inspected through 'showUnits'.
--
-- New constructors may be written by combining the provided ones, such as
--
-- >>> let newton = kilogram .* meter ./ (second .* second)
-- >>> 23*newton
-- 23.0 kg*m/s^2
-- <BLANKLINE>
-- >>> let g = 6.67408e-11 * newton .* (meter .* meter) ./ (kilogram .* kilogram)
-- >>> g -- gravitational constant
-- 6.67408e-11 m^3/kg*s^2
-- >>> let gravity m1 m2 r = g .* (m1 * kilogram) .* (m2 * kilogram) ./ (r*meter .* r*meter)
-- >>> let earth_mass = 5.972e24 * kilo gram
-- >>> let mars_mass = 6.417e23 * kilo gram
-- >>> let earth_radius = 6371 * kilo meter
-- >>> let mars_radius = 3389.5 * kilo meter
-- >>> let weight_on_earth mass = gravity mass earth_mass earth_radius
-- >>> let weight_on_mars mass = gravity mass mars_mass mars_radius
-- >>> weight_on_earth (80 * kilo gram)
-- 785.5719790179963 kg*m/s^2
-- >>> weight_on_mars (80 * kilo gram)
-- 298.22370259533704 kg*m/s^2
-- >>> weight_on_mars 1 / weight_on_earth 1
-- 0.3796261966575378 <adimensional>
newtype Quantity (us :: Units) a =
  Quantity {
    Quantity us a -> a
fromQuantity :: a -- ^Unwraps a 'Quantity', losing all unit information
  }
  deriving ( Quantity us a -> Quantity us a -> Bool
(Quantity us a -> Quantity us a -> Bool)
-> (Quantity us a -> Quantity us a -> Bool) -> Eq (Quantity us a)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (us :: Units) a.
Eq a =>
Quantity us a -> Quantity us a -> Bool
/= :: Quantity us a -> Quantity us a -> Bool
$c/= :: forall (us :: Units) a.
Eq a =>
Quantity us a -> Quantity us a -> Bool
== :: Quantity us a -> Quantity us a -> Bool
$c== :: forall (us :: Units) a.
Eq a =>
Quantity us a -> Quantity us a -> Bool
Eq
           , Eq (Quantity us a)
Eq (Quantity us a)
-> (Quantity us a -> Quantity us a -> Ordering)
-> (Quantity us a -> Quantity us a -> Bool)
-> (Quantity us a -> Quantity us a -> Bool)
-> (Quantity us a -> Quantity us a -> Bool)
-> (Quantity us a -> Quantity us a -> Bool)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> Ord (Quantity us a)
Quantity us a -> Quantity us a -> Bool
Quantity us a -> Quantity us a -> Ordering
Quantity us a -> Quantity us a -> Quantity us a
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall (us :: Units) a. Ord a => Eq (Quantity us a)
forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Bool
forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Ordering
forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Quantity us a
min :: Quantity us a -> Quantity us a -> Quantity us a
$cmin :: forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Quantity us a
max :: Quantity us a -> Quantity us a -> Quantity us a
$cmax :: forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Quantity us a
>= :: Quantity us a -> Quantity us a -> Bool
$c>= :: forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Bool
> :: Quantity us a -> Quantity us a -> Bool
$c> :: forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Bool
<= :: Quantity us a -> Quantity us a -> Bool
$c<= :: forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Bool
< :: Quantity us a -> Quantity us a -> Bool
$c< :: forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Bool
compare :: Quantity us a -> Quantity us a -> Ordering
$ccompare :: forall (us :: Units) a.
Ord a =>
Quantity us a -> Quantity us a -> Ordering
$cp1Ord :: forall (us :: Units) a. Ord a => Eq (Quantity us a)
Ord
           , Int -> Quantity us a
Quantity us a -> Int
Quantity us a -> [Quantity us a]
Quantity us a -> Quantity us a
Quantity us a -> Quantity us a -> [Quantity us a]
Quantity us a -> Quantity us a -> Quantity us a -> [Quantity us a]
(Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Int -> Quantity us a)
-> (Quantity us a -> Int)
-> (Quantity us a -> [Quantity us a])
-> (Quantity us a -> Quantity us a -> [Quantity us a])
-> (Quantity us a -> Quantity us a -> [Quantity us a])
-> (Quantity us a
    -> Quantity us a -> Quantity us a -> [Quantity us a])
-> Enum (Quantity us a)
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
forall (us :: Units) a. Enum a => Int -> Quantity us a
forall (us :: Units) a. Enum a => Quantity us a -> Int
forall (us :: Units) a. Enum a => Quantity us a -> [Quantity us a]
forall (us :: Units) a. Enum a => Quantity us a -> Quantity us a
forall (us :: Units) a.
Enum a =>
Quantity us a -> Quantity us a -> [Quantity us a]
forall (us :: Units) a.
Enum a =>
Quantity us a -> Quantity us a -> Quantity us a -> [Quantity us a]
enumFromThenTo :: Quantity us a -> Quantity us a -> Quantity us a -> [Quantity us a]
$cenumFromThenTo :: forall (us :: Units) a.
Enum a =>
Quantity us a -> Quantity us a -> Quantity us a -> [Quantity us a]
enumFromTo :: Quantity us a -> Quantity us a -> [Quantity us a]
$cenumFromTo :: forall (us :: Units) a.
Enum a =>
Quantity us a -> Quantity us a -> [Quantity us a]
enumFromThen :: Quantity us a -> Quantity us a -> [Quantity us a]
$cenumFromThen :: forall (us :: Units) a.
Enum a =>
Quantity us a -> Quantity us a -> [Quantity us a]
enumFrom :: Quantity us a -> [Quantity us a]
$cenumFrom :: forall (us :: Units) a. Enum a => Quantity us a -> [Quantity us a]
fromEnum :: Quantity us a -> Int
$cfromEnum :: forall (us :: Units) a. Enum a => Quantity us a -> Int
toEnum :: Int -> Quantity us a
$ctoEnum :: forall (us :: Units) a. Enum a => Int -> Quantity us a
pred :: Quantity us a -> Quantity us a
$cpred :: forall (us :: Units) a. Enum a => Quantity us a -> Quantity us a
succ :: Quantity us a -> Quantity us a
$csucc :: forall (us :: Units) a. Enum a => Quantity us a -> Quantity us a
Enum
           , Integer -> Quantity us a
Quantity us a -> Quantity us a
Quantity us a -> Quantity us a -> Quantity us a
(Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Integer -> Quantity us a)
-> Num (Quantity us a)
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
forall (us :: Units) a. Num a => Integer -> Quantity us a
forall (us :: Units) a. Num a => Quantity us a -> Quantity us a
forall (us :: Units) a.
Num a =>
Quantity us a -> Quantity us a -> Quantity us a
fromInteger :: Integer -> Quantity us a
$cfromInteger :: forall (us :: Units) a. Num a => Integer -> Quantity us a
signum :: Quantity us a -> Quantity us a
$csignum :: forall (us :: Units) a. Num a => Quantity us a -> Quantity us a
abs :: Quantity us a -> Quantity us a
$cabs :: forall (us :: Units) a. Num a => Quantity us a -> Quantity us a
negate :: Quantity us a -> Quantity us a
$cnegate :: forall (us :: Units) a. Num a => Quantity us a -> Quantity us a
* :: Quantity us a -> Quantity us a -> Quantity us a
$c* :: forall (us :: Units) a.
Num a =>
Quantity us a -> Quantity us a -> Quantity us a
- :: Quantity us a -> Quantity us a -> Quantity us a
$c- :: forall (us :: Units) a.
Num a =>
Quantity us a -> Quantity us a -> Quantity us a
+ :: Quantity us a -> Quantity us a -> Quantity us a
$c+ :: forall (us :: Units) a.
Num a =>
Quantity us a -> Quantity us a -> Quantity us a
Num
           , Num (Quantity us a)
Ord (Quantity us a)
Num (Quantity us a)
-> Ord (Quantity us a)
-> (Quantity us a -> Rational)
-> Real (Quantity us a)
Quantity us a -> Rational
forall a. Num a -> Ord a -> (a -> Rational) -> Real a
forall (us :: Units) a. Real a => Num (Quantity us a)
forall (us :: Units) a. Real a => Ord (Quantity us a)
forall (us :: Units) a. Real a => Quantity us a -> Rational
toRational :: Quantity us a -> Rational
$ctoRational :: forall (us :: Units) a. Real a => Quantity us a -> Rational
$cp2Real :: forall (us :: Units) a. Real a => Ord (Quantity us a)
$cp1Real :: forall (us :: Units) a. Real a => Num (Quantity us a)
Real
           , Enum (Quantity us a)
Real (Quantity us a)
Real (Quantity us a)
-> Enum (Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a
    -> Quantity us a -> (Quantity us a, Quantity us a))
-> (Quantity us a
    -> Quantity us a -> (Quantity us a, Quantity us a))
-> (Quantity us a -> Integer)
-> Integral (Quantity us a)
Quantity us a -> Integer
Quantity us a -> Quantity us a -> (Quantity us a, Quantity us a)
Quantity us a -> Quantity us a -> Quantity us a
forall a.
Real a
-> Enum a
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> (a, a))
-> (a -> a -> (a, a))
-> (a -> Integer)
-> Integral a
forall (us :: Units) a. Integral a => Enum (Quantity us a)
forall (us :: Units) a. Integral a => Real (Quantity us a)
forall (us :: Units) a. Integral a => Quantity us a -> Integer
forall (us :: Units) a.
Integral a =>
Quantity us a -> Quantity us a -> (Quantity us a, Quantity us a)
forall (us :: Units) a.
Integral a =>
Quantity us a -> Quantity us a -> Quantity us a
toInteger :: Quantity us a -> Integer
$ctoInteger :: forall (us :: Units) a. Integral a => Quantity us a -> Integer
divMod :: Quantity us a -> Quantity us a -> (Quantity us a, Quantity us a)
$cdivMod :: forall (us :: Units) a.
Integral a =>
Quantity us a -> Quantity us a -> (Quantity us a, Quantity us a)
quotRem :: Quantity us a -> Quantity us a -> (Quantity us a, Quantity us a)
$cquotRem :: forall (us :: Units) a.
Integral a =>
Quantity us a -> Quantity us a -> (Quantity us a, Quantity us a)
mod :: Quantity us a -> Quantity us a -> Quantity us a
$cmod :: forall (us :: Units) a.
Integral a =>
Quantity us a -> Quantity us a -> Quantity us a
div :: Quantity us a -> Quantity us a -> Quantity us a
$cdiv :: forall (us :: Units) a.
Integral a =>
Quantity us a -> Quantity us a -> Quantity us a
rem :: Quantity us a -> Quantity us a -> Quantity us a
$crem :: forall (us :: Units) a.
Integral a =>
Quantity us a -> Quantity us a -> Quantity us a
quot :: Quantity us a -> Quantity us a -> Quantity us a
$cquot :: forall (us :: Units) a.
Integral a =>
Quantity us a -> Quantity us a -> Quantity us a
$cp2Integral :: forall (us :: Units) a. Integral a => Enum (Quantity us a)
$cp1Integral :: forall (us :: Units) a. Integral a => Real (Quantity us a)
Integral
           , Num (Quantity us a)
Num (Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Rational -> Quantity us a)
-> Fractional (Quantity us a)
Rational -> Quantity us a
Quantity us a -> Quantity us a
Quantity us a -> Quantity us a -> Quantity us a
forall a.
Num a
-> (a -> a -> a) -> (a -> a) -> (Rational -> a) -> Fractional a
forall (us :: Units) a. Fractional a => Num (Quantity us a)
forall (us :: Units) a. Fractional a => Rational -> Quantity us a
forall (us :: Units) a.
Fractional a =>
Quantity us a -> Quantity us a
forall (us :: Units) a.
Fractional a =>
Quantity us a -> Quantity us a -> Quantity us a
fromRational :: Rational -> Quantity us a
$cfromRational :: forall (us :: Units) a. Fractional a => Rational -> Quantity us a
recip :: Quantity us a -> Quantity us a
$crecip :: forall (us :: Units) a.
Fractional a =>
Quantity us a -> Quantity us a
/ :: Quantity us a -> Quantity us a -> Quantity us a
$c/ :: forall (us :: Units) a.
Fractional a =>
Quantity us a -> Quantity us a -> Quantity us a
$cp1Fractional :: forall (us :: Units) a. Fractional a => Num (Quantity us a)
Fractional
           , Fractional (Quantity us a)
Quantity us a
Fractional (Quantity us a)
-> Quantity us a
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> (Quantity us a -> Quantity us a)
-> Floating (Quantity us a)
Quantity us a -> Quantity us a
Quantity us a -> Quantity us a -> Quantity us a
forall a.
Fractional a
-> a
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> Floating a
forall (us :: Units) a. Floating a => Fractional (Quantity us a)
forall (us :: Units) a. Floating a => Quantity us a
forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a -> Quantity us a
log1mexp :: Quantity us a -> Quantity us a
$clog1mexp :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
log1pexp :: Quantity us a -> Quantity us a
$clog1pexp :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
expm1 :: Quantity us a -> Quantity us a
$cexpm1 :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
log1p :: Quantity us a -> Quantity us a
$clog1p :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
atanh :: Quantity us a -> Quantity us a
$catanh :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
acosh :: Quantity us a -> Quantity us a
$cacosh :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
asinh :: Quantity us a -> Quantity us a
$casinh :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
tanh :: Quantity us a -> Quantity us a
$ctanh :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
cosh :: Quantity us a -> Quantity us a
$ccosh :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
sinh :: Quantity us a -> Quantity us a
$csinh :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
atan :: Quantity us a -> Quantity us a
$catan :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
acos :: Quantity us a -> Quantity us a
$cacos :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
asin :: Quantity us a -> Quantity us a
$casin :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
tan :: Quantity us a -> Quantity us a
$ctan :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
cos :: Quantity us a -> Quantity us a
$ccos :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
sin :: Quantity us a -> Quantity us a
$csin :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
logBase :: Quantity us a -> Quantity us a -> Quantity us a
$clogBase :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a -> Quantity us a
** :: Quantity us a -> Quantity us a -> Quantity us a
$c** :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a -> Quantity us a
sqrt :: Quantity us a -> Quantity us a
$csqrt :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
log :: Quantity us a -> Quantity us a
$clog :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
exp :: Quantity us a -> Quantity us a
$cexp :: forall (us :: Units) a.
Floating a =>
Quantity us a -> Quantity us a
pi :: Quantity us a
$cpi :: forall (us :: Units) a. Floating a => Quantity us a
$cp1Floating :: forall (us :: Units) a. Floating a => Fractional (Quantity us a)
Floating
           , a -> Quantity us b -> Quantity us a
(a -> b) -> Quantity us a -> Quantity us b
(forall a b. (a -> b) -> Quantity us a -> Quantity us b)
-> (forall a b. a -> Quantity us b -> Quantity us a)
-> Functor (Quantity us)
forall a b. a -> Quantity us b -> Quantity us a
forall a b. (a -> b) -> Quantity us a -> Quantity us b
forall (us :: Units) a b. a -> Quantity us b -> Quantity us a
forall (us :: Units) a b.
(a -> b) -> Quantity us a -> Quantity us b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Quantity us b -> Quantity us a
$c<$ :: forall (us :: Units) a b. a -> Quantity us b -> Quantity us a
fmap :: (a -> b) -> Quantity us a -> Quantity us b
$cfmap :: forall (us :: Units) a b.
(a -> b) -> Quantity us a -> Quantity us b
Functor
  )

instance (KnownSymbol (UnitRepr us), Show a) => Show (Quantity us a) where
  show :: Quantity us a -> String
show (Quantity a
x) = a -> String
forall a. Show a => a -> String
show a
x String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> KnownSymbol (UnitRepr us) => String
forall (us :: Units). KnownSymbol (UnitRepr us) => String
showUnits @us

instance Applicative (Quantity us) where
  pure :: a -> Quantity us a
pure = a -> Quantity us a
forall (us :: Units) a. a -> Quantity us a
Quantity
  Quantity a -> b
f <*> :: Quantity us (a -> b) -> Quantity us a -> Quantity us b
<*> Quantity a
x = b -> Quantity us b
forall (us :: Units) a. a -> Quantity us a
Quantity (a -> b
f a
x)