-- |'Hascal' is both a simple but extendable calculator library for Haskell -- and a command-line program using it. -- -- Also, its source code is a nice example for a minimalistic Haskell project. module Hascal ( -- * Functions -- ** Operators operators, -- ** Evaluators eval, hascal ) where import Control.Arrow (second) import Data.Function (on) import Data.Number.CReal -- |'operators' is the default list of operators. -- -- An operator consists of one character and a function with of type -- @CReal -> CReal -> CReal@. -- -- 'operators' includes: -- -- * addition, represented by @\'+\'@ -- -- * subtraction, represented by @\'-\'@ -- -- * multiplication, represented by @\'c\'@ -- -- * division, represented by @\'\/\'@ -- -- * exponentiation, represented by @\'^\'@ -- -- * logarithming (with flipped arguments, see below), represented by @\'?\'@ -- -- such that these laws are held: -- -- > (a - b == c) == (a == b + c) -- > (a / b == c) == (a == b * c) -- > (a ? b == c) == (a == b ^ c) operators :: [(Char, CReal -> CReal -> CReal)] operators = [ ('+', (+)) , ('-', (-)) , ('/', (/)) , ('*', (*)) , ('^', (**)) , ('?', flip logBase) ]-- Respecting operator precedence, -- you can add custom infix operators. -- |'eval' gets a list of operators and a string containing a mathematical -- expression/term which only uses those operators listed in the first -- argument, and returns the result of that term. eval :: [(Char, CReal -> CReal -> CReal)] -> String -> CReal eval [] a = read a eval l@((c,f):s) a | z /= "" = on f (eval l.($m)) fst snd | otherwise = eval s a where m@(_,z) = second (drop 1) $ break (==c) a -- |'hascal' is the default evaluator: -- -- > hascal = eval operators hascal :: String -> CReal hascal = eval operators