I didn't really understand this until today when I asked the following on hubFS:
"I'm wondering if the F# compiler has an optimization that will make it so that the sqrt5 and Phi functions only execute once, no matter how many times the fibn function is called, since the results of those functions are always constant.
let sqrt5 = sqrt 5.0
let Phi = (1.0 + sqrt5) / 2.0
let fibn n = Phi ** float n / sqrt5 |> round |> int
let fib2 = Seq.unfold (fun index -> Some (fibn index,index + 1)) 1
I'm trying to figure out if the compiler automagically makes this happen or if I have to make it happen."
Keith kindly broke it down (Thanks Keith!):
"In the code that you've written, sqrt5 and Phi are not functions but values (they don't take any arguments). As such, their definitions will never be re-evaluated... For top level definitions, something is a value if it doesn't take parameters. For instance, given the two definitions:
let now = System.DateTime.Now
let add x y = x + y
"now" is a value, and will never change. add is a function taking two arguments, and each time both arguments are supplied, the definition on the right will be evaluated to give the return value.
However, when defining .NET classes, things become more complicated, because classes can contain fields, methods, events, properties, etc. Properties are re-evaluated whenever they are gotten, and DateTime.Now is a property, which is why the value appears to change over time.
Things can also be a bit confusing when using functions in a first-class way. For instance:
let myFun =
let time = System.DateTime.Now
fun () -> System.DateTime.Now - time
Here, myFun is a value (which happens to be a function!), and its definition is only evaluated once (so, in particular, "time" is only ever set once, when myFun is first defined). However, calling the myFun function then results in the evaluation of the function's body (that is, the right hand side of the last line of myFun's definition, which calls System.DateTime.Now and subtracts the original time)."