Reputation: 2985
Why our functions need to take a state and an input and not just a state that includes the input (or an input that includes the state?).
I assume that you might want to apply different inputs with the same state and therefore you want to keep them separately, but is that the only reason?
I feel that I'm missing something fundamental, but I can't grasp it.
Upvotes: 2
Views: 146
Reputation: 1575
Terminology: if you are new to Haskell it is easy to get confused/fooled by statements like "State data is mutable". Someone coming from imperative programs might take "mutable" to mean change the value in an existing location. For some parts of Haskell (e.g., IORef
) that is indeed true. In the State
monad case it is not true.
State
supports mutating a state into a NEW state - the new state is completely independent of the old state. Nothing is mutated in place.
Sometimes this is called "effectful" programming - you get the benefits of effects but without using "real" side-effects - State
is completely pure.
Upvotes: 0
Reputation: 43309
I'm not entirely sure what your actual question is but here are some facts that could probably answer it:
State data is mutable (via the State
monad), input data is immutable. In Haskell it's conventional to achieve maximum of type-level safety. If you unite input with state you'll make it mutable too for no purpose.
Monads do not have inputs. You might be thinking about arrows. And in fact there is a state arrow.
Upvotes: 1
Reputation: 27549
The State monad is useful because it enforces a pattern which is obvious from the type.
Instead of having every function in your code look like:
foo state x y = ... return (state', z)
you can use State
to make clear what your intent is.
Upvotes: 0
Reputation: 1918
That's due to the conveniency. In general, separate arguments, if they are conceptually separated (I mean, they aren't properties of a single object, for example), are better than packed in a datatype, because in the former case you can use currying, combinators and other advantages of functional approach.
Without monads, each stateful function would look like foo :: b -> s -> (s, a)
, and with monads, we can extract the common part, name it: newtype State s a = State (s -> (s, a))
, and define return
and >>=
for it. Moreover, any simple function bar :: a -> b
can be easily turned into a stateful via a simple change of the result: bar :: a -> State s b
. That would be impossible if both input and state were carried in a single argument (say, a tuple: foo :: (s, a) -> (s, a)
.
Upvotes: 1