What would be the functional programming equivalent of the State design pattern? Or more concretely, how would this Wikipedia example of State design pattern will translate to FP?
4 Answers
This pattern is an example of the use of the State monad, a computational environment tha augments code with state.
Here's an implementation in Haskell.
Some helpers:
import Control.Monad.Trans.State
import Control.Monad.IO.Class
import Data.Char
The two modes of operation of the program
data Mode = A | B
The type of stateful computations with this mode, augmented with a counter.
type StateM a = StateT (Int, Mode) IO a
The write function, a function in the StateM context, changes its behavior based on the stateful mode:
writeName :: String -> StateM ()
writeName s = do
(n,mode) <- get
case mode of
A -> do liftIO (putStrLn (map toLower s))
put (0,B)
B -> do let n' = n + 1
liftIO (putStrLn (map toUpper s))
if n' > 1 then put (n', A)
else put (n', B)
Run the program, launching a stateful computation initially in state A
main = flip runStateT (0, A) $ do
writeName "Monday"
writeName "Tuesday"
writeName "Wednesday"
writeName "Thursday"
writeName "Saturday"
writeName "Sunday"
From the above code, the output of main is:
monday
TUESDAY
WEDNESDAY
thursday
SATURDAY
SUNDAY
Note that this is a purely functional solution. There is no mutable or destructive updates in this program. Instead, the state monad threads the desired mode through the computation.

- 137,316
- 36
- 365
- 468
-
1I wouldn't say this is a faithful encoding: here we have to declare all modes in one place (`data Mode`), whereas in the wikipedia example declarations can be combined modularly. – luqui Jun 11 '11 at 14:45
-
That's the standard translation to closed data types in ML-style languages. Obviously, we could step out an use open data types via functions or type classes, but I think it is not relevant for this problem. – Don Stewart Jun 11 '11 at 14:47
-
1I am curious what it is a standard translation from, and what you mean by standard. – luqui Jun 11 '11 at 14:52
-
3I'm arguing that the *idiomatic* thing is to translate objects with multiple variants to an algebraic data type. – Don Stewart Jun 11 '11 at 15:01
One encoding:
import Data.Char (toUpper, toLower)
newtype State = State { unState :: String -> IO State }
stateA :: State
stateA = State $ \name -> do
putStrLn (map toLower name)
return stateB
stateB :: State
stateB = go 2
where
go 0 = stateA
go n = State $ \name -> do
putStrLn (map toUpper name)
return $ go (n-1)
Don't be fooled by the IO
, this is a pure translation of that pattern (we are not using an IORef
to store the state or anything). Expanding the newtype
, we see what this type means:
State = String -> IO (String -> IO (String -> IO (String -> ...
It takes a string, does some I/O and asks for another string, etc.
This is my favorite encoding of abstract class patterns in OO: abstract class -> type, subclasses -> elements of that type.
The newtype State
declaration takes the place of the abstract writeName
declaration and its signature. Instead of passing a StateContext
into which we assign a new state, we just have it return the new state. Embedding the return value in IO
says that the new state is allowed to depend on I/O. Since that is not technically necessary in this example, we could use the more stringent type
newtype State = State { unState :: String -> (State, IO ()) }
in which we can still express this computation, but the sequence of states is fixed and not allowed to depend on input. But let's stick to the original, more lenient type.
And for the "test client":
runState :: State -> [String] -> IO ()
runState s [] = return ()
runState s (x:xs) = do
s' <- unState s x
runState s' xs
testClientState :: IO ()
testClientState = runState stateA
[ "Monday"
, "Tuesday"
, "Wednesday"
, "Thursday"
, "Saturday"
, "Sunday" ]

- 59,485
- 12
- 145
- 204
-
P.S. You'll need to capture the counter toggling semantics as well. – Don Stewart Jun 11 '11 at 14:47
-
For what it's worth, I'd say this style of encoding is ideal only for true OO-idiomatic classes encapsulating abstracted behavior. A depressing number of "classes" in allegedly OO code are much closer to clumsy translations of the style Don used and thus benefit from being turned back into what they wanted to be in the first place... – C. A. McCann Jun 12 '11 at 03:23
Maybe with a State
monad combined with custom modifiers and accessors?

- 88,405
- 25
- 200
- 352
-
Agreed, looks like a particular use of the `State` monad to me too. – Don Stewart Jun 11 '11 at 14:23
I don't think there's pure functional equivalent for state pattern. Because pure functional programming doesn't have the concept of state and time. State pattern is intrinsically about state and time. But I think the non-pure functional equivalent exists, it's infinite lazy evaluated stream. You can implement it with C# yield.

- 24,586
- 26
- 88
- 133
-
1FP indeed has state. Never heard of monads? There is even something called functional reactive programming to capture time-varying state. – fuz Jun 11 '11 at 14:24
-
-
1I don't think "has" is the right word to connect "functional programming" and "state". I like to think of it as "models" -- we can do stateful computations by building a functional model of what state means. – luqui Jun 11 '11 at 14:28
-
1@Todd monads are completely pure. You can carry any kind of state within them. There is also STM, which provides the concept of modifyable local variables. Even STM is pure in the sense that you can prove, that a function that uses STM in the designated way is referentially transparent. State may be not the most popular idiom though. – fuz Jun 11 '11 at 14:29
-
1
-
@FUZxxl To be frank, I don't fully understand monads. How do you think of infinite lazy evaluated stream? Is it functional? If you think it's functional, i agree monads can be functional. – Dagang Jun 11 '11 at 14:38
-
@Todd Let's define »pure« as referential transparent and »functional« as ideomatic for functional programming. Then both of your things are functional, but the first on may or may not be pure, since on must be careful about the order of evaluation when using infinite streams of IO. – fuz Jun 11 '11 at 16:24
-
1@luqui: I think "has" is a viable word, actually, in a rough sense of "is available for use and manipulation". As such, a pure language has *the concept of state*, whereas an impure language merely has *intrinsic state*. Thus the seeming paradox that Haskell has far more tools for manipulating imperative computations than any imperative language could. – C. A. McCann Jun 12 '11 at 03:15