hid-examples-0.3: expr/EvalRPN_trans.hs
module EvalRPN_trans (evalRPN) where
import Control.Monad.State
import Safe
{-
Function evalRPN evaluates an expression given
in the reversed polish notation (RPN, postfix notation):
evalRPN "2 3 +" ==> 5 (== "2 + 3")
evalRPN "2 3 4 + *" ==> 14 (== 2 * (3 + 4))
-}
type Stack = [Integer]
type EvalM = StateT Stack Maybe
push :: Integer -> EvalM ()
push x = modify (x:)
pop :: EvalM Integer
pop = do
xs <- get
guard (not $ null xs)
put (tail xs)
pure (head xs)
-- lift (headMay xs)
oneElementOnStack :: EvalM ()
oneElementOnStack = do
l <- length <$> get
guard (l == 1)
-- when (l /= 1) $ lift Nothing
readSafe :: String -> EvalM Integer
readSafe s = lift (readMay s)
evalRPN :: String -> Maybe Integer
evalRPN str = evalStateT evalRPN' []
where
evalRPN' = traverse step (words str) >> oneElementOnStack >> pop
step "+" = processTops (+)
step "*" = processTops (*)
step t = readSafe t >>= push
processTops op = op <$> pop <*> pop >>= push