Overlord Zurg
Overlord Zurg

Reputation: 3794

Is it possible to represent mutability without using mutability?

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

Answers (2)

Lee
Lee

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

ritcoder
ritcoder

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

Related Questions