Reputation: 3794
After reading this excellent series on state monads (and other... things), I tried to reproduce the following scenario without using a mutable variable (adapted from a simple UI that counts clicks):
let mutable count = 1
let increment () = count <- count + 1
I couldn't come up with a way to do it.
Could this be handled in F# without using mutable variables? How is it handled by other functional languages which don't allow immutability at all? Or am I asking the wrong questions?
Upvotes: 0
Views: 293
Reputation: 144136
The functional alternative to mutating variables is to return an updated value from a function. Stateful computations can be modelled by functions which take the current value of the state and return a pair containing the result and the updated value of the state. You can define such a type in F# as
type State<'s, 'a> = S of ('s -> ('s * 'a))
which just wraps a stateful function. You can then define some functions for manipulating stateful functions:
let returnState x = S (fun s -> (s, x))
let runState (S(f)) s = f s
let putState s = S (fun _ -> (s, ()))
let getState<'s, 'a> = S (fun (s: 's) -> (s, s))
returnState
creates a stateful computation which ignores the state and returns the given value. runState
runs a stateful computation with a given initial state. putState
is a stateful computation which gets the current state, while putState
updates the current state and returns a dummy value.
You can then combine stateful computations with the following function:
let bindState<'s, 'a, 'b> (S(sf): State<'s, 'a>) (f : 'a -> State<'s, 'b>) = S (fun s ->
let (s', r) = sf s
let (S(sf')) = f r
sf' s')
this takes a stateful computation and a function to construct a new computation given the result value from the first. It then constructs a compound computation which will run the first computation, use the value to construct the next computation and then run that given with the intermediate state returned from the first computation.
This forms a monad so you can create a computation expression and use it to make stateful computations with a more convenient syntax:
type StateBuilder() =
member this.Return(x) = returnState x
member this.Bind(s, f) = bindState s f
member this.ReturnFrom(s: State<_,_>) = s
let state = StateBuilder()
let modifyState f = state {
let! s = getState
let s' = f s
return! (putState s')
}
modifyState
takes a function a -> a
to transform the value of the state in a computation. You can then write a function to increment the value of a counter in a stateful computation:
let incState = modifyState ((+)1)
Upvotes: 4
Reputation: 3304
If you are not using mutable variables, you can use ref variables. With it, your code will look like this
let count = ref 1
let increment() = count := !count + 1
I'm not particular about the two though I used mutable more often than ref. Found this stackoverflow link which is a good read also on the differences between the two.
Upvotes: -1