Skip to content

Instantly share code, notes, and snippets.

@Solonarv
Created November 18, 2018 00:46
Show Gist options
  • Save Solonarv/79799f9aaf4746620f0188fe7d34d08b to your computer and use it in GitHub Desktop.
Save Solonarv/79799f9aaf4746620f0188fe7d34d08b to your computer and use it in GitHub Desktop.
Simple RPN calculator. Takes the program from command-line arguments.
module Main where
import System.Environment (getArgs)
import Control.Applicative
import Data.Maybe
import Text.Read
main :: IO ()
main = do
program <- parse . unwords <$> getArgs
putStrLn . unwords . reverse . fmap show $ eval program
type Val = Integer
type Op = Val -> Val -> Val
data Instr = Push Val | Exec Op
parse :: String -> [Instr]
parse = mapMaybe parseWord . words
where
parseWord w = (Push <$> readMaybe w) <|> (Exec <$> lookup w ops)
ops :: [(String, Op)]
ops =
[ ("+", (+))
, ("-", (-))
, ("*", (*))
]
eval :: [Instr] -> [Val]
eval prog = eval' prog []
eval' :: [Instr] -> [Val] -> [Val]
eval' [] vs = vs
eval' (i:is) vs = case i of
Push v -> eval' is (v:vs)
Exec op -> case vs of
x:y:rest -> eval' is ((op x y):rest)
_ -> error "Not enough arguments!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment