Last active
June 4, 2023 09:24
-
-
Save mengwong/73af81ad600a533f12ef42fc655fed0f to your computer and use it in GitHub Desktop.
evalRWST (RWST r w s (Either String) a) returns Either String (a, w) instead of (Either String a, w)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
This library demonstrates the difference between | |
RWST (Either String) a | |
RWS (Either String a) | |
The first form outputs | |
1 + 2, after bonus = Right (103,[]) | |
5 + 10, after bonus = Right (115,["10 is a big number"]) | |
12 + 19, after bonus = Right (131,["12 is a big number","19? I might run out of toes"]) | |
12 + 30, after bonus = Left "30 is too big, I can't count that high" | |
But we would prefer it to output | |
(Right 103, []) | |
(Right 115, ["10 is a big number"]) | |
(Right 131, ["12 is a big number","19? I might run out of toes"]) | |
(Left "30 is too big, I can't count that high", ["12 is a big number"]) | |
And that's what the second form does. | |
-} | |
module Lib | |
( someFunc | |
) where | |
import Data.Map as Map ( Map, (!), fromList ) | |
import Control.Monad.RWS.Strict ( RWST, lift, evalRWST, asks, tell | |
, RWS, evalRWS ) | |
import Control.Applicative (liftA2) | |
someFunc :: IO () | |
someFunc = sequence_ | |
[ putStrLn $ show i ++ " + " ++ show j ++ ", after bonus = " ++ | |
show ( evalRWST | |
( myBonusT $ myAddT i j ) | |
(fromList [("bonus", 100)]) | |
mempty ) | |
| (i, j) <- [ (1,2), (5,10), (12,19), (12,30) ] | |
] | |
>> someFunc2 | |
type MyMT = RWST (Map String Int) [String] (Map String String) (Either String) | |
myAddT :: Int -> Int -> MyMT Int | |
myAddT x y = do | |
x' <- myValT x | |
y' <- myValT y | |
return (x' + y') | |
myValT :: Int -> MyMT Int | |
myValT n | |
| n < 10 = return n | |
| n < 15 = tell [show n ++ " is a big number"] >> return n | |
| n < 20 = mutterT (show n ++ "? I might run out of toes") >> return n | |
| otherwise = lift $ Left (show n ++ " is too big, I can't count that high") | |
mutterT :: String -> MyMT () | |
mutterT s = tell [s] | |
myBonusT :: MyMT Int -> MyMT Int | |
myBonusT n = (+) <$> asks (! "bonus") <*> n | |
-- * Maybe having the Either String as a base monad for the transformer is too much. | |
-- Let's do another version as a plain RWS. | |
type MyM' a = RWS (Map String Int) [String] (Map String String) a | |
type MyM b = MyM' (Either String b) | |
someFunc2 :: IO () | |
someFunc2 = sequence_ | |
[ putStrLn $ show i ++ " + " ++ show j ++ ", after bonus = " ++ | |
show ( evalRWS | |
( myBonus $ myAdd i j ) | |
(fromList [("bonus", 100)]) | |
mempty ) | |
| (i, j) <- [ (1,2), (5,10), (12,19), (12,30) ] | |
] | |
myAdd :: Int -> Int -> MyM Int | |
myAdd x y = do | |
x' <- myVal x | |
y' <- myVal y | |
return ((+) <$> x' <*> y') | |
myVal :: Int -> MyM Int | |
myVal n | |
| n < 10 = return (Right n) | |
| n < 15 = tell [show n ++ " is a big number"] >> return (pure n) | |
| n < 20 = mutter (show n ++ "? I might run out of toes") >> pure (pure n) | |
| otherwise = pure $ Left (show n ++ " is too big, I can't count that high") | |
mutter :: String -> MyM' () | |
mutter s = tell [s] | |
myBonus :: MyM Int -> MyM Int | |
myBonus n = do | |
n' <- n | |
b' <- Right <$> asks (! "bonus") | |
return ((+) <$> b' <*> n') | |
myBonus' :: MyM Int -> MyM Int | |
myBonus' n = liftA2 (+) <$> (Right <$> asks (! "bonus")) <*> n |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Remark:
16:45 < ncf> freeside: the second form should be equivalent to ExceptT String RWS a, if you want to stick to monad transformers
16:54 < ncf> (and then you can rewrite your functions to work equally well with both versions, using mtl-style classes)