packages feed

significant-figures-0.2.0.0: src/Data/SigFig/Types.hs

{-# LANGUAGE ImportQualifiedPost #-}

-- |
-- Basic types and convenience functions for constructing your own terms and expression trees.
module Data.SigFig.Types
  ( Term (..),
    Op (..),
    Expr (..),
    Function (..),

    -- * Creating Terms and Expression Trees
    measured,
    constant,
    l,
    lMeasured,
    lConstant,

    -- * Building and Combining Expression Trees
    add,
    sub,
    mul,
    div,
    exp,
    apply,
  )
where

import Data.BigDecimal (BigDecimal (..))
import Data.BigDecimal qualified as BD
import Prelude hiding (div, exp)

-- | The basic datatype to represent measurements, constant terms, and evaluation results
data Term
  = -- | A measured value with a finite number of significant figures and an associated value
    Measured {numSigFigs :: Integer, value :: BigDecimal}
  | -- | A constant value with infinite significant figures
    Constant Rational
  deriving (Show, Eq)

-- | Create a measured value
measured :: Integer -> Rational -> Term
measured sf = Measured sf . fromRational

-- | Create a constant value
constant :: Rational -> Term
constant = Constant

toConstant :: Term -> Term
toConstant (Measured _ bd) = Constant $ toRational bd
toConstant a = a

-- | The types of (infix) operators
data Op
  = Add
  | Sub
  | Mul
  | Div
  deriving (Show, Eq, Bounded, Enum)

-- | Create a literal node out of a term, like a "singleton".
l :: Term -> Expr
l = Literal

-- | Create a literal node and construct the 'Measured' value argument at the same time. Convenience function.
lMeasured :: Integer -> Rational -> Expr
lMeasured = (l .) . measured

-- | Create a literal node and construct the 'Constant' value argument at the same time. Convenience function.
lConstant :: Rational -> Expr
lConstant = l . constant

-- | Add together a list of 'Expr's and create a new 'Expr'.
--
-- @add a b c@ is similar in idea to @a + b + c@.
add :: [Expr] -> Expr
add = Prec1 . zip (repeat Add)

-- | "Subtract together" a list of 'Expr's and create a new 'Expr'.
--
-- @sub a b c@ is similar in idea to @a - b - c@.
sub :: [Expr] -> Expr
sub [] = Prec1 []
sub (x : xs) = Prec1 $ (Add, x) : zip (repeat Sub) xs

-- | multiply together a list of 'Expr's and create a new 'Expr'.
--
-- @mul a b c@ is similar in idea to @a * b * c@.
mul :: [Expr] -> Expr
mul = Prec2 . zip (repeat Mul)

-- | "Divide together" a list of 'Expr's and create a new 'Expr'.
--
-- @div a b c@ is similar in idea to @a \/ b \/ c@.
div :: [Expr] -> Expr
div [] = Prec2 []
div (x : xs) = Prec2 $ (Mul, x) : zip (repeat Div) xs

-- | Take an 'Expr' to the power of an integer. Equivalent to 'Exp'.
exp :: Expr -> Expr -> Expr
exp = Exp

-- | Apply a function to an 'Expr'. Equivalent to 'Apply'.
apply :: Function -> Expr -> Expr
apply = Apply

-- | A datatype representing the supported functions.
data Function
  = -- | The function @log()@ in expressions.
    Log10
  | -- | The function @exp()@ in expressions.
    Antilog10
  deriving (Show, Eq, Bounded, Enum)

-- | A datatype to represent (not-yet-evaluated) expressions. Use 'Data.SigFig.Parse.parse' to create such an expression from text.
data Expr
  = -- | Literal term
    Literal Term
  | -- | Operation of "Precedence 1": addition and subtraction
    Prec1 [(Op, Expr)]
  | -- | Operation of "Precedence 2": multiplication and division
    Prec2 [(Op, Expr)]
  | -- | Exponentiation with a constant exponent
    Exp Expr Expr
  | -- | Application of a function to an expression argument
    Apply Function Expr
  deriving (Show, Eq)