Most F# material does explain that all top-level statements in a module are executed from top-down on declaration. In other words, what you've declared isn't a function, but a value which is bound once when the program runs.
It really helps to see the reflected code. I have a simple file:
let juliet = "awesome"
let juliet2() = "awesome"
The compiled code looks something like this:
public static string juliet
{
[CompilerGenerated, DebuggerNonUserCode]
get
{
return "awesome";
}
}
//...
public static string juliet2()
{
return "awesome";
}
So one is a static property, the other is a function. This is a desirable property, because imagine if we had something like this:
let x = someLongRunningDatabaseCall()
We only want x
to be bound once, we don't want it to invoke database function everytime we access x
.
Additionally, we can write interesting code like this:
> let isInNebraska =
printfn "Creating cities set"
let cities = set ["Omaha"; "Bellevue"; "Lincoln"; "Papillion"; "La Vista"; "Ralston"]
fun n -> cities.Contains(n);;
Creating cities set
val isInNebraska : (string -> bool)
> isInNebraska "Omaha";;
val it : bool = true
> isInNebraska "Okaloosa";;
val it : bool = false
Since isInNebraska
is a value, its evaluated immediately. It just so happens that its datatype is (string -> bool)
, so it looks like a function. As a result, we only fill our cities
set once even if we invoke the function 1000 times.
Let's compare that code to this:
> let isInNebraska2 n =
printfn "Creating cities set"
let cities = set ["Omaha"; "Bellevue"; "Lincoln"; "Papillion"; "La Vista"; "Ralston"]
cities.Contains(n);;
val isInNebraska2 : string -> bool
> isInNebraska2 "Omaha";;
Creating cities set
val it : bool = true
> isInNebraska2 "Okaloosa";;
Creating cities set
val it : bool = false
Oops, we're creating a new cities set everytime we invoke the function.
So there is definitely a legitimate and real distinction between values and functions.