numerals-0.4.1: src/Text/Numeral/Exp.hs
module Text.Numeral.Exp
( Exp(..)
, showExp
-- , eval
, evalScale
, Side(L, R)
) where
-------------------------------------------------------------------------------
-- Imports
-------------------------------------------------------------------------------
import qualified "this" Text.Numeral.Grammar as G
-------------------------------------------------------------------------------
-- Expression type
-------------------------------------------------------------------------------
-- | An expression that represents the structure of a numeral.
data Exp
= Unknown
-- ^ An unknown value. This is used to signal that a value can
-- not be represented in the expression language.
| Lit Integer
-- ^ A literal value.
--
-- Example in English:
--
-- > "three" = Lit 3
| Neg Exp
-- ^ Negation of an expression.
--
-- Example in English:
--
-- > "minus two" = Neg (Lit 2)
| Add Exp Exp
-- ^ Addition of two expressions.
--
-- Example in English:
--
-- > "fifteen" = Lit 5 `Add` Lit 10
| Mul Exp Exp
-- ^ Multiplication of two expressions.
--
-- Example in English:
--
-- > "thirty" = Lit 3 `Mul` Lit 10
| Sub Exp Exp
-- ^ One expression subtracted from another expression.
--
-- Example in Latin:
--
-- > "duodēvīgintī" = Lit 2 `Sub` (Lit 2 `Mul` Lit 10)
| Frac Exp Exp
-- ^ A fraction.
--
-- Example in English:
--
-- > "two thirds" = `Frac` (Lit 2) (Lit 3)
| Scale Integer Integer Exp
-- ^ A step in a scale of large values.
--
-- Should be interpreted as @10 ^ (rank * base + offset)@.
--
-- Example in English:
--
-- > "quadrillion" = Scale 3 3 4
| ChangeCase (Maybe G.Case ) Exp
| ChangeGender (Maybe G.Gender) Exp
-- ^ A change of grammatical gender.
--
-- This is used in a language like Spanish where the inflection
-- of a number word is not always constant. Specifically, in
-- Spanish, large number names always have the masculine
-- gender. So 'millón', 'billón' and the like are all
-- masculine. This can result in the following number word:
-- 10000001 = "un (masculine) millón una (feminine)"
--
-- Example in Spanish (with the context being Feminine):
--
-- > "un millón una" = ChangeGender (Just Masculine) (Lit 1) `Mul` Scale 3 3 1 `Add` Lit 1
| ChangeNumber (Maybe G.Number) Exp
infixl 6 `Add`
infixl 6 `Sub`
infixl 7 `Mul`
showExp :: Exp -> String
showExp Unknown = "Unknown"
showExp (Lit n) = "Lit " ++ show n
showExp (Neg x) = "Neg (" ++ showExp x ++ ")"
showExp (Add x y) = "Add (" ++ showExp x ++ ") (" ++ showExp y ++ ")"
showExp (Mul x y) = "Mul (" ++ showExp x ++ ") (" ++ showExp y ++ ")"
showExp (Sub x y) = "Sub (" ++ showExp x ++ ") (" ++ showExp y ++ ")"
showExp (Frac x y) = "Frac (" ++ showExp x ++ ") (" ++ showExp y ++ ")"
showExp (Scale b o r) = "Scale " ++ show b ++ " " ++ show o ++ " (" ++ showExp r ++ ")"
showExp (ChangeCase mbC x) = "Case is " ++ show mbC ++ " in (" ++ showExp x ++ ")"
showExp (ChangeGender mbG x) = "Gender is " ++ show mbG ++ " in (" ++ showExp x ++ ")"
showExp (ChangeNumber mbN x) = "Number is " ++ show mbN ++ " in (" ++ showExp x ++ ")"
evalScale :: (Integral a) => a -> a -> a -> a
evalScale b o r = 10 ^ (r*b + o)
-- eval :: (Fractional a) => Exp -> Maybe a
-- eval (Lit x) = pure x
-- eval (Add x y) = (+) <$> eval x <*> eval y
-- eval (Mul x y) = (*) <$> eval x <*> eval y
-- eval (Sub x y) = subtract <$> eval x <*> eval y
-- eval (Neg x) = negate <$> eval x
-- eval (Frac n d) = (/) <$> eval n <*> eval d
-- eval (Scale b o r) = evalScale (fromInteger b) (fromInteger o) <$> eval r
-- eval (ChangeCase _ x) = eval x
-- eval (ChangeGender _ x) = eval x
-- eval (ChangeNumber _ x) = eval x
-- eval Unknown = Nothing
-------------------------------------------------------------------------------
-- Side
-------------------------------------------------------------------------------
-- | A side or direction, either 'L'eft or 'R'ight.
data Side = L -- ^ Left.
| R -- ^ Right.
deriving (Eq, Show)