packages feed

deepcontrol-0.3.2.0: test/unit_Monad-Level2.hs

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
    ]