62 lines
2.6 KiB
Haskell
62 lines
2.6 KiB
Haskell
-- hc - haskell command line calculator using rational numbers
|
|
-- Copyright (C) 2024 VegOwOtenks
|
|
--
|
|
-- This program is free software: you can redistribute it and/or modify
|
|
-- it under the terms of the GNU Affero General Public License as published by
|
|
-- the Free Software Foundation, either version 3 of the License, or
|
|
-- (at your option) any later version.
|
|
--
|
|
-- This program is distributed in the hope that it will be useful,
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-- GNU Affero General Public License for more details.
|
|
--
|
|
-- You should have received a copy of the GNU Affero General Public License
|
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
--
|
|
-- contact me via vegowotenks at jossco dot de
|
|
module Main (main) where
|
|
|
|
import Lib (exprparser, evaluate, replaceVars, Expr, extractVariableDefinitions, updateVariables, parseFullString)
|
|
|
|
import Data.Map (Map)
|
|
import qualified Data.Map as Map
|
|
import Data.Ratio
|
|
|
|
import System.IO
|
|
|
|
initVars :: Map String Rational
|
|
initVars = Map.fromList [("pi", 245850922 % 78256779), ("e", 271801 % 99990)]
|
|
|
|
main :: IO ()
|
|
main = ioLoop initVars
|
|
|
|
precision = 5 :: Int
|
|
|
|
showRatio :: Int -> Rational -> String
|
|
showRatio p r = (if (r < 0) then "-" else "") ++ prepoint_digits ++ (if (length postpoint_digits > 0) then ("." ++ postpoint_digits) else "")
|
|
where
|
|
prepoint_digits = init . show . round . abs $ (r * 10)
|
|
postpoint_digits = reverse . dropWhile (=='0') . reverse .(take p) . (drop (length prepoint_digits)) . show . round . abs $ (r * 10^p)
|
|
|
|
useResult :: Map String Rational -> Expr -> String
|
|
useResult vs expr = either id ((showRatio precision) . evaluate) $ replaceVars expr vs
|
|
|
|
ioLoop :: Map String Rational -> IO ()
|
|
ioLoop vs = do done <- isEOF
|
|
if done
|
|
then putStrLn "Quit!"
|
|
else do inp <- getLine
|
|
let expr_res = parseFullString inp
|
|
case expr_res of
|
|
Left err -> do
|
|
putStrLn . show $ err
|
|
ioLoop vs
|
|
Right expr -> do
|
|
let vardefs = extractVariableDefinitions expr
|
|
let uvs_res = updateVariables vardefs vs
|
|
case uvs_res of
|
|
Left err -> putStrLn err
|
|
Right uvs -> putStrLn $ useResult uvs expr
|
|
ioLoop (either (const vs) (id) uvs_res)
|
|
|