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)