I don’t understand the exact algebra and theory behind Haskell’s monads. However, when I think about functional programming in general I get the impression that state would be modelled by taking an initial state and generating a copy of it to represent the next state. This is like when one list is appended to another; neither list gets modified, but a third list is created and returned.
Is it therefore valid to think of monadic operations as implicitly taking an initial state object as a parameter and implicitly returning a final state object? These state objects would be hidden so that the programmer doesn’t have to worry about them and to control how they gets accessed. So, the programmer would not try to copy the object representing the IO stream as it was ten minutes ago.
In other words, if we have this code:
main = do
putStrLn "Enter your name:"
name <- getLine
putStrLn ( "Hello " ++ name )
…is it OK to think of the IO monad and the “do” syntax as representing this style of code?
putStrLn :: IOState -> String -> IOState
getLine :: IOState -> (IOState, String)
main :: IOState -> IOState
-- main returns an IOState we can call "state3"
main state0 = putStrLn state2 ("Hello " ++ name)
where (state2, name) = getLine state1
state1 = putStrLn state0 "Enter your name:"
No, that’s not what monads in general do. However, your analogy is in fact exactly correct with regards to the data type
State s a, which happens to be a monad.Stateis defined like this:…where the type variable
sis the state value andais the “regular” value that you use. So a value in “the State monad” is just a function from an initial state, to a return value and final state. The monadic style, as applied toState, does nothing more than automatically thread a state value through a sequence of functions.The
STmonad is superficially similar, but uses magic to allow computations with real side-effects, but only such that the side effects can’t be observed from outside particular uses ofST.The
IOmonad is essentially anSTmonad set to “more magic”, with side effects that touch the outside world and only a single point whereIOcomputations are run, namely the entry point for the entire program. Still, on some conceptual level, you can still think of it as threading a “state” value through functions the way regularStatedoes.However, other monads don’t necessarily have anything whatsoever to do with threading state, or sequencing functions, or whatnot. The operations needed for something to be a monad are incredibly general and abstract. For instance, using
MaybeorEitheras monads lets you use functions that might return errors, with the monadic style handling escaping from the computation when an error occurs the same way thatStatethreads a state value. Using lists as a monad gives you nondeterminism, letting you simultaneously apply functions to multiple inputs and see all possible outputs, with the monadic style automatically applying the function to each argument and collecting all the outputs.