The F# language doesn’t have a different notion of a statement and an expression, which means that every language construct is an expression with a known return type. If the construct performs only a side effect (for example printing to a screen or modifying a global mutable variable or a state of .NET object) and doesn’t return any value then the type of the construct is unit, which is a type with only one possible value (written as “()”). The semicolon symbol (;) is used for sequencing multiple expressions, but the first expression in the sequence should have a unit as a result type. The following example demonstrates how the if construct can be used as an expression in F# (though in the optional F# lightweight syntax, which makes whitespace significant and which we used in the rest of this overview, the semicolon symbol can be omitted):
> let n = 1
let res =
if n = 1 then
printfn "..n is one..";
"one"
else
"something else";;
..n is one..
val res : string = "one"
When this code executes it calls the true branch of the if expression, which first calls a side-effecting function, which prints a string and then returns a string ("one") as the result. The result is then assigned to the res value.
Unlike some languages that allow one variable name to appear only once in the entire function body (e.g. C#) or even treat all variables declared inside the body of a function as a variable with scope of the whole function (e.g. Visual Basic or JavaScript), the scope of F# values is determined by the let binding and it is allowed to hide a value by declaring a value with the same name. The following (slightly esoteric) example demonstrates this:
> let n = 21
let f =
if n < n =" n"> print_int n)
else
let n = n / 2
(fun () -> print_int n)
let n = 0
f ();;
42
val it : unit
In this example, the value n declared inside a branch of the if expression is captured by a function created using the fun keyword, which is returned from the if expression and bound to the value named f. When the f is invoked it indeed uses the value from the scope where it was created, which is 42. In languages, where the variable named n would refer to a value stored globally, it would be rather problematic to write a code like this. Of course, writing a code similar to what I demonstrated in this example isn't a good idea, because it makes the code very difficult to read. There are however situations where hiding a value that is no longer needed in the code is practical.
> let n = 1
let res =
if n = 1 then
printfn "..n is one..";
"one"
else
"something else";;
..n is one..
val res : string = "one"
When this code executes it calls the true branch of the if expression, which first calls a side-effecting function, which prints a string and then returns a string ("one") as the result. The result is then assigned to the res value.
Unlike some languages that allow one variable name to appear only once in the entire function body (e.g. C#) or even treat all variables declared inside the body of a function as a variable with scope of the whole function (e.g. Visual Basic or JavaScript), the scope of F# values is determined by the let binding and it is allowed to hide a value by declaring a value with the same name. The following (slightly esoteric) example demonstrates this:
> let n = 21
let f =
if n < n =" n"> print_int n)
else
let n = n / 2
(fun () -> print_int n)
let n = 0
f ();;
42
val it : unit
In this example, the value n declared inside a branch of the if expression is captured by a function created using the fun keyword, which is returned from the if expression and bound to the value named f. When the f is invoked it indeed uses the value from the scope where it was created, which is 42. In languages, where the variable named n would refer to a value stored globally, it would be rather problematic to write a code like this. Of course, writing a code similar to what I demonstrated in this example isn't a good idea, because it makes the code very difficult to read. There are however situations where hiding a value that is no longer needed in the code is practical.
Post a Comment