F# Code Execution Order
another noob question regarding F#.
If I have the following code...
let ExeC =
printfn "c"
3
let ExeB b =
printfn "b"
2
let ExeA =
printfn "a"
1
printfn "Example %d " ExeA
printfn "Example %d " (ExeB 1)
printfn "Example %d " ExeC
The output is as follows...
c
a
Example 1
b
Example 2
Example 3
What seems unusual here is the order that the code is executing in. In a previous question Brian mentioned something about expressions, I was hoping someone could explain this a bit more. It almost seems like the compiler is intelligentl开发者_高级运维y pre-executing things to calculate values... but I don't know?
ExeA
and ExeC
aren't functions, but single values. The compiler ensures that values initialise in the order in which they're declared in the source file, so what's happening here is:
ExeC
initialisesExeA
initialisesExample 1
is printed, usingExeA
's initialised value- The
ExeB
function is called as normal Example 3
is printed, usingExeC
's initialised value
If you want ExeA
and ExeC
to be truly lazy -- that is, to control when their side effects run -- you could turn them into functions that accept unit
:
let ExeC () =
printfn "c"
3
let ExeB b =
printfn "b"
2
let ExeA () =
printfn "a"
1
printfn "Example %d " (ExeA ())
printfn "Example %d " (ExeB 1)
printfn "Example %d " (ExeC ())
As a follow up to Tim's answer, I thought you might appreciate some further insight into what you've stumbled upon. In your example, ExeC and ExeA take advantage of the functional style of organizing code through lexical scoping and closures. Let me demonstrate a more powerful example.
let calc n =
//...
let timesPieDiv4 =
let pie = 3.14
let pieDiv4 = pie/4.
n * pieDiv4
//...
Here again timesPieDiv4
is not a function, but does have a body which contains a series of sub calculations which are not exposed to the rest of the calc
function. In a language like C#, you have two options neither of which appeals to me. The first option is to simply declare pie
and pieDiv4
within the main body of calc
, but then it's less clear how they are being used and you dirty your variable space. The other option is to factor those sub calculations out into a separate private helper function. But I dislike such functions, because with many it becomes hard to analyze your complex algorithms since you are constantly darting around looking up various implementation pieces. Plus it's a lot of boiler plate code and value passing. That's why F# functions are "public" by default, lexical scoping and closures allow you to hierarchically organize "private" functions and values within your public facing functions.
精彩评论