{-# 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: -- -- >>> 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 -- -- >>> 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 * kilogram -- >>> let mars_mass = 6.417e23 * kilogram -- >>> let earth_radius = 6371e3 * meter -- >>> let mars_radius = 3389.5e3 * 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 * kilogram) -- 785.5719790179963 kg*m/s^2 -- >>> weight_on_mars (80 * kilogram) -- 298.22370259533704 kg*m/s^2 -- >>> fromQuantity $ weight_on_mars 1 / (fromQuantity $ weight_on_earth 1) -- 0.3796261966575378 newtype Quantity (us :: Units) a = Quantity { fromQuantity :: a -- ^Unwraps a @Quantity@, losing all unit information } deriving ( Eq , Ord , Enum , Num , Real , Integral , Fractional , Floating , Functor ) instance (KnownSymbol (UnitRepr us), Show a) => Show (Quantity us a) where show (Quantity x) = show x <> " " <> showUnits @us instance Applicative (Quantity us) where pure = Quantity Quantity f <*> Quantity x = Quantity (f x)