0

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?

Overlord Zurg
  • 3,430
  • 2
  • 22
  • 27
  • 2
    What does "I was unsuccessful" mean? What happened, or what error did you get? – TeaDrivenDev Aug 06 '15 at 21:07
  • 1
    https://wiki.haskell.org/Mutable_variable – Mauricio Scheffer Aug 06 '15 at 21:14
  • 2
    just a quick comment: all practical relevant languages I know (including Haskell of course) will allow you to mutate some state at some point (and be it to update your database) the idea in pure langs. is to push this out to the boundaries of your application as far as possible (in Haskell this would probably be the infamous `IO` type in the `main`) - F# is not pure and it's usually seen as ok - in your example the majority of F#ers would not use a StateMonad (as you cannot build MonadStacks without man. rewrite this is not an option most of the time anyways) – Random Dev Aug 07 '15 at 04:27

2 Answers2

3

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)
Lee
  • 142,018
  • 20
  • 234
  • 287
-1

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.

Community
  • 1
  • 1
ritcoder
  • 3,274
  • 10
  • 42
  • 62
  • `ref` semantically has the same effect; it's just treated a bit differently by the compiler (and not necessary anymore in F# 4). To the downvoter: A downvote without at least explaining why is extremely unhelpful and pointless. Just don't do that. – TeaDrivenDev Aug 06 '15 at 21:09
  • A link was added in the post on the difference between them even if there is a lot of similarity between them. Is that what warrants a down vote? – ritcoder Aug 06 '15 at 21:34
  • I believe downvote comes from the fact that mutability is understood in the context of functional programming, not the particular `mutable` keyword. So the answer is very misleading because it could lead some people to believe `ref` is correct way to avoid mutability. – Grozz Aug 06 '15 at 22:01
  • @TeaDrivenDev while I basically agree that you should give some hints of why you downvote it's the **meta** here that you don't have to - indeed it's designed so that you can downvote and upvote in private - head over to META and discuss (again ;) ) if you want (and need some downvotes there) – Random Dev Aug 07 '15 at 04:22