2010-07-03 99 views
8

另一個關於F#的noob問題。F#代碼執行順序

如果我有以下代碼...

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 

的輸出如下...

c 
a 
Example 1 
b 
Example 2 
Example 3 

什麼似乎是不尋常這裏是代碼在執行的順序。在之前的問題Brian提到了有關表情的一些問題,我希望有人能夠更多地解釋這一點。它幾乎看起來像編譯器智能預執行的東西來計算值...但我不知道?

回答

13

ExeAExeC不是函數,而是單個值。編譯器可以確保值初始化在其源文件中要聲明的順序,所以這裏發生了什麼是:

  1. ExeC初始化
  2. ExeA初始化
  3. Example 1打印,使用ExeA的初始化值
  4. ExeB函數被稱爲正常
  5. Example 3被印刷,使用ExeC的初始化值

如果你想ExeAExeC是真正的懶惰 - 也就是說,它們的副作用運行時控制 - 你可以把它們變成接受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()) 
3

作爲後續根據Tim的回答,我認爲你可能會對你遇到的問題有進一步的瞭解。在您的示例中,ExeC和ExeA通過詞法範圍和關閉來利用組織代碼的功能風格。讓我演示一個更強大的例子。

let calc n = 
    //... 
    let timesPieDiv4 = 
     let pie = 3.14 
     let pieDiv4 = pie/4. 
     n * pieDiv4 

    //... 

這裏再次timesPieDiv4不是一個函數,但確實有一個包含一系列未暴露在calc函數的其餘部分分計算的身體。在像C#這樣的語言中,你有兩種選擇對我沒有吸引力。第一種選擇是簡單地在calc的主體內聲明piepieDiv4,但不清楚它們是如何被使用的,並且你弄髒了你的可變空間。另一種選擇是將這些子計算分解成單獨的私人幫助函數。但是我不喜歡這樣的功能,因爲很多時候你很難分析你的複雜算法,因爲你經常在尋找各種實現部分。另外它還有很多鍋爐板代碼和價值傳遞。這就是爲什麼默認情況下F#函數是「公共」的原因,詞法範圍和閉包允許您在面向公共職能的層次上組織「私有」函數和值。

+0

謝謝史蒂芬 - 欣賞進一步的闡述! – 2010-07-04 07:02:02