import Test.HUnit hiding (State) import DeepControl.Applicative import DeepControl.Traversable (sinkmap) import DeepControl.Monad ((>-)) import DeepControl.Monad.Morph import DeepControl.Monad.Trans import DeepControl.Monad.Trans.Identity import Control.Monad.Except import Control.Monad.State import Control.Monad.Trans.Maybe ----------------------------------------------- -- State push :: a -> State [a] a push x = do xs <- get put (x:xs) return x pop :: State [a] a pop = do xs <- get put (tail xs) return (head xs) -- > runState (push 1 >> push 2 >> push 3) [] -- (3,[3,2,1]) -- > runState (push 1 >> push 2 >> push 3 >> pop >> pop) [] -- (2,[1]) poland :: String -> State [Double] Double poland "+" = do x <- pop y <- pop push (y + x) poland "-" = do x <- pop y <- pop push (y - x) poland "*" = do x <- pop y <- pop push (y * x) poland "/" = do x <- pop y <- pop push (y / x) poland x = push (read x :: Double) poland_calc :: [String] -> (Double, [Double]) poland_calc xs = (sinkmap poland xs >> pop) >- \x -> runState x [] -- > poland_calc ["1","2","*"] -- (2.0, []) -- > poland_calc ["1","2","-"] -- (-1.0, []) -- > poland_calc ["1","2","+","3","*"] -- (9.0, []) -- > poland_calc ["1","2","+","3","*","3","/"] -- (3.0, []) -- > poland_calc ["1","2","+","3","*","0","/"] -- (Infinity, []) ----------------------------------------------- -- StateT-Maybe pushS :: a -> StateT [a] Maybe a pushS x = do xs <- get put (x:xs) return x popS :: StateT [a] Maybe a popS = do xs <- get put (tail xs) return (head xs) -- > runStateT (pushT 1 >> pushT 2 >> pushT 3) [] -- Just (3,[3,2,1]) -- > runStateT (pushT 1 >> pushT 2 >> pushT 3 >> popT >> popT) [] -- Just (2,[1]) polandS :: String -> StateT [Double] Maybe Double polandS "+" = do x <- popS y <- popS pushS (y + x) polandS "-" = do x <- popS y <- popS pushS (y - x) polandS "*" = do x <- popS y <- popS pushS (y * x) polandS "/" = do x <- popS y <- popS guard (x /= 0) pushS (y / x) polandS x = pushS (read x :: Double) poland_calcS :: [String] -> Maybe (Double, [Double]) poland_calcS xs = (sinkmap polandS xs >> popS) >- \x -> runStateT x [] -- > poland_calcS ["1","2","*"] -- Just (2.0, []) -- > poland_calcS ["1","2","-"] -- Just (-1.0, []) -- > poland_calcS ["1","2","+","3","*"] -- Just (9.0, []) -- > poland_calcS ["1","2","+","3","*","3","/"] -- Just (3.0, []) -- > poland_calcS ["1","2","+","3","*","0","/"] -- Nothing ----------------------------------------------- -- MaybeT-StateT-IO Monad pushMS :: a -> MaybeT (StateT [a] IO) a pushMS x = do xs <- get put (x:xs) return x popMS :: MaybeT (StateT [a] IO) a popMS = do xs <- get put (tail xs) return (head xs) polandMS :: String -> MaybeT (StateT [Double] IO) Double polandMS "+" = do x <- popMS y <- popMS liftIO $ putStrLn (show y ++" + "++ show x ++" = "++ show (y + x)) pushMS (y + x) polandMS "-" = do x <- popMS y <- popMS liftIO $ putStrLn (show y ++" - "++ show x ++" = "++ show (y - x)) pushMS (y - x) polandMS "*" = do x <- popMS y <- popMS liftIO $ putStrLn (show y ++" * "++ show x ++" = "++ show (y * x)) pushMS (y * x) polandMS "/" = do x <- popMS y <- popMS liftIO $ putStr (show y ++" / "++ show x ++" = ") guard (x /= 0) liftIO $ putStr (show (y / x) ++"\n") pushMS (y / x) polandMS x = pushMS (read x :: Double) poland_calcMS :: [String] -> IO (Maybe Double, [Double]) poland_calcMS xs = (sinkmap polandMS xs >> popMS) >- runMaybeT >- \x -> runStateT x [] -- > poland_calcS2 ["1","2","*"] -- 1.0 * 2.0 = 2.0 -- (Just 2.0, []) ----------------------------------------------- -- StateT-MaybeT-IO Monad pushSM :: a -> StateT [a] (MaybeT IO) a pushSM x = do xs <- get put (x:xs) return x popSM :: StateT [a] (MaybeT IO) a popSM = do xs <- get put (tail xs) return (head xs) polandSM :: String -> StateT [Double] (MaybeT IO) Double polandSM "+" = do x <- popSM y <- popSM liftIO $ putStrLn (show y ++" + "++ show x ++" = "++ show (y + x)) pushSM (y + x) polandSM "-" = do x <- popSM y <- popSM liftIO $ putStrLn (show y ++" - "++ show x ++" = "++ show (y - x)) pushSM (y - x) polandSM "*" = do x <- popSM y <- popSM liftIO $ putStrLn (show y ++" * "++ show x ++" = "++ show (y * x)) pushSM (y * x) polandSM "/" = do x <- popSM y <- popSM liftIO $ putStr (show y ++" / "++ show x ++" = ") guard (x /= 0) liftIO $ putStr (show (y / x) ++"\n") pushSM (y / x) polandSM x = pushSM (read x :: Double) poland_calcSM :: [String] -> IO (Maybe (Double, [Double])) poland_calcSM xs = (sinkmap polandSM xs >> popSM) >- \x -> runStateT x [] >- runMaybeT ----------------------------------------------- -- StateT-Identity2-IO-Maybe Monad pushSI2 :: a -> StateT [a] (IdentityT2 IO Maybe) a pushSI2 x = do xs <- get put (x:xs) return x popSI2 :: StateT [a] (IdentityT2 IO Maybe) a popSI2 = do xs <- get put (tail xs) return (head xs) polandSI2 :: String -> StateT [Double] (IdentityT2 IO Maybe) Double polandSI2 "+" = do x <- popSI2 y <- popSI2 liftIO $ putStrLn (show y ++" + "++ show x ++" = "++ show (y + x)) pushSI2 (y + x) polandSI2 "-" = do x <- popSI2 y <- popSI2 liftIO $ putStrLn (show y ++" - "++ show x ++" = "++ show (y - x)) pushSI2 (y - x) polandSI2 "*" = do x <- popSI2 y <- popSI2 liftIO $ putStrLn (show y ++" * "++ show x ++" = "++ show (y * x)) pushSI2 (y * x) polandSI2 "/" = do x <- popSI2 y <- popSI2 liftIO $ putStr (show y ++" / "++ show x ++" = ") guard (x /= 0) liftIO $ putStr (show (y / x) ++"\n") pushSI2 (y / x) polandSI2 x = pushSI2 (read x :: Double) poland_calcSI2 :: [String] -> IO (Maybe (Double, [Double])) poland_calcSI2 xs = (sinkmap polandSI2 xs >> popSI2) >- \x -> runStateT x [] >- runIdentityT2 ----------------------------------------------- -- StateT-IdentityT-MaybeT-IO popSIM :: StateT [a] (MaybeT IO) a popSIM = (transroll2 . runIdentityT2) |>| popSI2 polandSIM :: String -> StateT [Double] (MaybeT IO) Double polandSIM s = (transroll2 . runIdentityT2) |>| polandSI2 s poland_calcSIM :: [String] -> IO (Maybe (Double, [Double])) poland_calcSIM xs = (sinkmap polandSIM xs >> popSIM) >- \x -> runStateT x [] >- runMaybeT ----------------------------------------------- -- StateT-MaybeT-ExceptT-IO Monad pushSME :: a -> StateT [a] (MaybeT (ExceptT () IO)) a pushSME x = do xs <- get put (x:xs) return x popSME :: StateT [a] (MaybeT (ExceptT () IO)) a popSME = do xs <- get put (tail xs) return (head xs) polandSME :: String -> StateT [Double] (MaybeT (ExceptT () IO)) Double polandSME "+" = do x <- popSME y <- popSME liftIO $ putStrLn (show y ++" + "++ show x ++" = "++ show (y + x)) pushSME (y + x) polandSME "-" = do x <- popSME y <- popSME liftIO $ putStrLn (show y ++" - "++ show x ++" = "++ show (y - x)) pushSME (y - x) polandSME "*" = do x <- popSME y <- popSME liftIO $ putStrLn (show y ++" * "++ show x ++" = "++ show (y * x)) pushSME (y * x) polandSME "/" = do x <- popSME y <- popSME liftIO $ putStr (show y ++" / "++ show x ++" = ") guard (x /= 0) liftIO $ putStr (show (y / x) ++"\n") pushSME (y / x) polandSME x = pushSME (read x :: Double) poland_calcSME :: [String] -> IO (Either () (Maybe (Double, [Double]))) poland_calcSME xs = (sinkmap polandSME xs >> popSME) >- \x -> runStateT x [] >- runMaybeT >- runExceptT ----------------------------------------------- -- StateT-IdentityT-MaybeT-ExceptT-IO pushSIME :: a -> StateT [a] (IdentityT (MaybeT (ExceptT () IO))) a pushSIME x = IdentityT |>| pushSME x popSIME :: StateT [a] (IdentityT (MaybeT (ExceptT () IO))) a popSIME = IdentityT |>| popSME polandSIME :: String -> StateT [Double] (IdentityT (MaybeT (ExceptT () IO))) Double polandSIME x = IdentityT |>| polandSME x poland_calcSIME :: [String] -> IO (Either () (Maybe (Double, [Double]))) poland_calcSIME xs = (sinkmap polandSIME xs >> popSIME) >- \x -> runStateT x [] >- runIdentityT >- runMaybeT >- runExceptT ----------------------------------------------- -- StateT-IdentityT3-IO-Except-Maybe pushSI3 :: a -> StateT [a] (IdentityT3 IO (Except ()) Maybe) a pushSI3 x = (IdentityT3 . untransroll3 . runIdentityT) |>| pushSIME x popSI3 :: StateT [a] (IdentityT3 IO (Except ()) Maybe) a popSI3 = (IdentityT3 . untransroll3 . runIdentityT) |>| popSIME polandSI3 :: String -> StateT [Double] (IdentityT3 IO (Except ()) Maybe) Double polandSI3 x = (IdentityT3 . untransroll3 . runIdentityT) |>| polandSIME x poland_calcSI3 :: [String] -> IO (Either () (Maybe (Double, [Double]))) poland_calcSI3 xs = (sinkmap polandSI3 xs >> popSI3) >- \x -> runStateT x [] >- runIdentityT3 >- (runExcept|$>) ---------------------------------------------------------------- -- unit test ---------------------------------------------------------------- main :: IO () main = do runTestTT tests_ putStrLn "" >> print "---------- S -----------" runTestTT tests_S putStrLn "" >> print "---------- MS -----------" runTestTT tests_MS putStrLn "" >> print "---------- SM -----------" runTestTT tests_SM putStrLn "" >> print "---------- SI2 -----------" runTestTT tests_SI2 putStrLn "" >> print "---------- SIM -----------" runTestTT tests_SIM putStrLn "" >> print "---------- SIME -----------" runTestTT tests_SIME putStrLn "" >> print "---------- SI3 -----------" runTestTT tests_SI3 putStrLn "" >> print "---------------------" return () tests_ :: Test tests_ = test [ "poland" ~: do let actual = poland_calc ["1","2","*"] actual @?= (2.0, []) let actual = poland_calc ["1","2","+","3","*","3","/"] actual @?= (3.0, []) --actual <- poland_calc ["1","2","+","3","*","0","/"] --actual @?= Infinity ] tests_S :: Test tests_S = test [ "polandT" ~: do let actual = poland_calcS ["1","2","*"] actual @?= Just (2.0, []) let actual = poland_calcS ["1","2","+","3","*","3","/"] actual @?= Just (3.0, []) let actual = poland_calcS ["1","2","+","3","*","0","/"] actual @?= Nothing ] tests_MS :: Test tests_MS = test [ "polandMS" ~: do actual <- poland_calcMS ["1","2","*"] actual @?= (Just 2.0, []) actual <- poland_calcMS ["1","2","+","3","*","3","/"] actual @?= (Just 3.0, []) actual <- poland_calcMS ["1","2","+","3","*","0","/"] actual @?= (Nothing, []) ] tests_SM :: Test tests_SM = test [ "polandSM" ~: do actual <- poland_calcSM ["1","2","*"] actual @?= Just (2.0, []) actual <- poland_calcSM ["1","2","+","3","*","3","/"] actual @?= Just (3.0, []) actual <- poland_calcSM ["1","2","+","3","*","0","/"] actual @?= Nothing ] tests_SI2 :: Test tests_SI2 = test [ "polandSI2" ~: do actual <- poland_calcSI2 ["1","2","*"] actual @?= Just (2.0, []) actual <- poland_calcSI2 ["1","2","+","3","*","3","/"] actual @?= Just (3.0, []) actual <- poland_calcSI2 ["1","2","+","3","*","0","/"] actual @?= Nothing ] tests_SIM :: Test tests_SIM = test [ "polandSIM" ~: do actual <- poland_calcSIM ["1","2","*"] actual @?= Just (2.0, []) actual <- poland_calcSIM ["1","2","+","3","*","3","/"] actual @?= Just (3.0, []) actual <- poland_calcSIM ["1","2","+","3","*","0","/"] actual @?= Nothing ] tests_SIME :: Test tests_SIME = test [ "polandSIME" ~: do actual <- poland_calcSIME ["1","2","*"] actual @?= Right (Just (2.0, [])) actual <- poland_calcSIME ["1","2","+","3","*","3","/"] actual @?= Right (Just (3.0, [])) actual <- poland_calcSIME ["1","2","+","3","*","0","/"] actual @?= Right Nothing ] tests_SI3 :: Test tests_SI3 = test [ "polandSI3" ~: do actual <- poland_calcSI3 ["1","2","*"] actual @?= Right (Just (2.0, [])) actual <- poland_calcSI3 ["1","2","+","3","*","3","/"] actual @?= Right (Just (3.0, [])) actual <- poland_calcSI3 ["1","2","+","3","*","0","/"] actual @?= Right Nothing ]