Thoughts On Variable Expressions In OCaml and F#

RecursiveEnigma
TechDev Mix
Published in
3 min readApr 11, 2015

--

As a F# developer, I was surprised to get the following error “Parse error: “in” expected after [binding] (in [expr])”, while working on an OCaml project. Well it turns out I’ve been using the in keyword in F# all along.

So what’s going on here? It’s is all related to the scope of variable expressions. Consider the following F# code:

module Order =

let name = "Module scope"

let processOrder () =
printfn "1. %s" name

let doesSomething =
let name = "doesSomething scope"
printfn "2. %s" name

let doesSomethingElse =
let name = "doesSomethingElse nested scope 1"
printfn "3. %s" name

let name = "doesSomethingElse nested scope 2"
printfn "4. %s" name

printfn "5. %s" name

When run, the above writes:

1. Module scope
2. doesSomething scope
3. doesSomethingElse nested scope 1
4. doesSomethingElse nested scope 2
5. Module scope

The above code demonstrates that every time you use let (without binding it to a value) you create a new inner scope inside of an outer scope. A variable from the outer scope or the same scope can be re-declared and assigned a new value within its scope. The variable will then have the new value from that point onwards in the same and child scopes, but the parent outer scope will retain its original value. That is why every time name gets bound to a new value, the most recent value is written out. In other words a variable can “shadow” or “hide” other variables from the parent scope, or preceding variables.

The last value printed, means that once the redefined definitions of a variable in child scopes are complete, the original value of name reappears.

What is also demonstrated is that each let scope is executed from top to bottom, and that redefinitions in child scopes can’t affect parent scopes. However, in order for a computation to change a variable in a parent “upstream” scope, requires mutation of a variable or using reference cells

Okay, so now let’s get back to the in keyword, and the OCaml error message I got. The previous code example can be rewritten in F# to use the in keyword:

module Order =

let name = "Module scope"

let processOrder () =
printfn "1. %s" name

let doesSomething =
let name = "doesSomething scope"
in printfn "2. %s" name

let doesSomethingElse =
let name = "doesSomethingElse nested scope 1"
in printfn "3. %s" name

let name = "doesSomethingElse nested scope 2"
in printfn "4. %s" name

in printfn "5. %s" name

Another example. This:

let a () =
let
x = 5
let y = x + 2
let z = y + x + 3
x + y + z

Actually means:

let a () =
let
x = 5 in
let y = x + 2 in
let z = y + x + 3 in
x + y + z

So now you can see that every time you bind a variable, what is actually happening is that you are creating an expression, whose result is restricted to the following child expressions, building up to a final larger computation, in the form of:


let
<variable> = <some expression> in
<child expression using parent expression>

And this brings me to my final point, that the difference between OCaml and F# is that OCaml requires you to always use the “in” version when you declare variables, whereas F# supports both forms of declaring variable expressions.

--

--