import Test.HUnit hiding (State) import DeepControl.Applicative import DeepControl.Monad ((>-)) import DeepControl.Commutative (cmap) import DeepControl.Monad.Trans import DeepControl.Monad.Trans.State import DeepControl.Monad.Trans.Except import Control.Monad.Trans.Maybe import Control.Monad.Identity ----------------------------------------------- -- 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 = (cmap 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 lift $ guard (x /= 0) pushS (y / x) polandS x = pushS (read x :: Double) poland_calcS :: [String] -> Maybe (Double, [Double]) poland_calcS xs = (cmap 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 = (cmap 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 = (cmap polandSM xs >> popSM) >- \x -> runStateT x [] >- runMaybeT ----------------------------------------------- -- StateT2-IO-Maybe polandS2' :: String -> StateT2 [Double] IO Maybe Double polandS2' s = untransfold2 $ polandSM s poland_calcS2' :: [String] -> IO (Maybe (Double, [Double])) poland_calcS2' xs = (cmap polandS2' xs >> popS2) >- \x -> runStateT2 x [] ----------------------------------------------- -- StateT2-IO-Maybe pushS2 :: a -> StateT2 [a] IO Maybe a pushS2 x = do xs <- get put (x:xs) return x popS2 :: StateT2 [a] IO Maybe a popS2 = do xs <- get put (tail xs) return (head xs) polandS2 :: String -> StateT2 [Double] IO Maybe Double polandS2 "+" = do x <- popS2 y <- popS2 liftIO $ putStrLn (show y ++" + "++ show x ++" = "++ show (y + x)) pushS2 (y + x) polandS2 "-" = do x <- popS2 y <- popS2 liftIO $ putStrLn (show y ++" - "++ show x ++" = "++ show (y - x)) pushS2 (y - x) polandS2 "*" = do x <- popS2 y <- popS2 liftIO $ putStrLn (show y ++" * "++ show x ++" = "++ show (y * x)) pushS2 (y * x) polandS2 "/" = do x <- popS2 y <- popS2 liftIO $ putStr (show y ++" / "++ show x ++" = ") lift2 $ (*:) $ guard (x /= 0) liftIO $ putStr (show (y / x) ++"\n") pushS2 (y / x) polandS2 x = pushS2 (read x :: Double) poland_calcS2 :: [String] -> IO (Maybe (Double, [Double])) poland_calcS2 xs = (cmap polandS2 xs >> popS2) >- \x -> runStateT2 x [] -- > poland_calcS2 ["1","2","*"] -- 1.0 * 2.0 = 2.0 -- Just (2.0, []) -- > poland_calcS2 ["1","2","+","3","*"] -- 1.0 + 2.0 = 3.0 -- 3.0 * 3.0 = 9.0 -- Just (9.0, []) -- > poland_calcS2 ["1","2","+","3","*","3","/"] -- 1.0 + 2.0 = 3.0 -- 3.0 * 3.0 = 9.0 -- 9.0 / 3.0 = 3.0 -- Just (3.0, []) -- > poland_calcS2 ["1","2","+","3","*","0","/"] -- 1.0 + 2.0 = 3.0 -- 3.0 * 3.0 = 9.0 -- 9.0 / 0.0 = Nothing ----------------------------------------------- -- 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 = (cmap polandSME xs >> popSME) >- \x -> runStateT x [] >- runMaybeT >- runExceptT ----------------------------------------------- -- StateT3-IO-Except-Maybe Monad pushS3 :: a -> StateT3 [a] IO (Except ()) Maybe a pushS3 x = do xs <- get put (x:xs) return x popS3 :: StateT3 [a] IO (Except ()) Maybe a popS3 = do xs <- get put (tail xs) return (head xs) polandS3 :: String -> StateT3 [Double] IO (Except ()) Maybe Double polandS3 s = untransfold3 $ polandSME s poland_calcS3 :: [String] -> IO (Either () (Maybe (Double, [Double]))) poland_calcS3 xs = (cmap polandS3 xs >> popS3) >- \x -> runStateT3 x [] >- (runExcept |$>) ---------------------------------------------------------------- -- unit test ---------------------------------------------------------------- main :: IO () main = do runTestTT tests_Level0 putStrLn "" >> print "---------------------" runTestTT tests_Level1 putStrLn "" >> print "---------------------" runTestTT tests_Level1_2 putStrLn "" >> print "---------------------" runTestTT tests_Level1_3 putStrLn "" >> print "---------------------" runTestTT tests_Level2 putStrLn "" >> print "---------------------" runTestTT tests_Level2_2 putStrLn "" >> print "---------------------" runTestTT tests_Level3 putStrLn "" >> print "---------------------" runTestTT tests_Level3_2 putStrLn "" >> print "---------------------" return () tests_Level0 :: Test tests_Level0 = 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_Level1 :: Test tests_Level1 = 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_Level1_2 :: Test tests_Level1_2 = 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_Level1_3 :: Test tests_Level1_3 = 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_Level2 :: Test tests_Level2 = test [ "polandS2" ~: do actual <- poland_calcS2 ["1","2","*"] actual @?= Just (2.0, []) actual <- poland_calcS2 ["1","2","+","3","*","0","/"] actual @?= Nothing ] tests_Level2_2 :: Test tests_Level2_2 = test [ "polandS2'" ~: do actual <- poland_calcS2' ["1","2","*"] actual @?= Just (2.0, []) actual <- poland_calcS2' ["1","2","+","3","*","0","/"] actual @?= Nothing ] tests_Level3 :: Test tests_Level3 = test [ "polandSME'" ~: do actual <- poland_calcSME ["1","2","*"] actual @?= Right (Just (2.0, [])) actual <- poland_calcSME ["1","2","+","3","*","0","/"] actual @?= Right Nothing ] tests_Level3_2 :: Test tests_Level3_2 = test [ "polandS3" ~: do actual <- poland_calcS3 ["1","2","*"] actual @?= Right (Just (2.0, [])) actual <- poland_calcS3 ["1","2","+","3","*","0","/"] actual @?= Right Nothing ]