Let State' be my program state with some data.
type State' m a = StateT Int m a
I would use it in some computations.
Examples:
-- genData, return some string (using Int value and State')
genData :: Int -> State' String
genData n = ...
-- genDatas, return multiple strings
genDatas :: Int -> State' [String]
genDatas n = mapM genData [1..n]
-- printLog, write log message (enumerating lines)
printLog :: String -> State' IO ()
printLog msg = do
n <- get
let n' = n + 1
put n'
liftIO $ putStrLn $ "Message #" ++ (show n') ++ ": " ++ msg
I think is not the correct way do it:
-- If I need a "in context function" returning a Int value...
--
-- addExtra, return current Int in state plus x
addExtra :: Int -> State' Identity Int
addExtra x = get >>= return.(+x)
To use my addExtra function in some monad context I do it:
doComplex :: State' IO ()
doComplex = do
printLog "Starting process..."
-- It's ugly!
s <- get
Identity (w, s') <- return $ runStateT (addExtra 5) s
put s' -- save state
printLog $ "computed value: " ++ (show w)
What is the correct way to share my State' monad along different functions? (as IO a is doing)
Thank you!
(I have read some tutorials and some source codes but I can’t understand it)
Answering your question
Since your
addExtrafunction doesn’t actually do anything with the underlying monad, you can just change the type signature to make it monad-agnostic:Now you can write this
Which is much prettier, and works just like your old code:
Aside
I’d probably be tempted to rewrite
addExtrato one of the following. First, either use do notationor to use
liftM, since we’re not really using the fact that we have a monador even to use
gets(thanks to Daniel Wagner in the comments)Of course, by this point you probably don’t need the additional function. You may as well just write
Similarly, I’d probably rewrite
printLog. If you ever find yourselfgeting the state, doing something to it, andputing it back, you probably just want to usemodify.