2010-09-21 65 views
1

F#中的(..)和(.. ..)運算符在某個時間點展開,是編譯時操作還是運行時操作?是在編譯時或運行時評估的F#範圍

無論哪種情況,這是什麼表現?即是否可以構建一個自定義函數來更快地完成這些操作?

+0

編寫它,編譯它,並用反射器檢查出來。如果你看到它展開......這是編譯時間。如果沒有,它是運行時(我會嘗試它,但我目前沒有工具)。 – 2010-09-21 17:40:14

+0

如果您問是否可以構建自定義函數來比語言內置的功能更快地評估理解 - 也許。像軟件開發中的大多數事情一樣,答案將取決於上下文。 – 2010-09-21 20:57:18

回答

3

我認爲的回覆kvb回答了大部分問題。但是,我認爲更準確的答案是,在運行時間處懶惰地評估範圍。這裏有一些更詳細的信息如何範圍工作...

當你使用例如1 .. 10在你的代碼中的某個地方,它只是轉換爲一些方法調用。調用取決於使用的上下文和數字類型。

  • 對於[ 1 .. 10 ]或其它序列表達式和for循環,編譯器會生成類似RangeInt32(1, 1, 10)(附加參數是步驟)。

  • 當您有類似obj.[ 1 .. ]obj是一些對象,它支持分片(例如矩陣型),那麼它會被轉換爲obj.GetSlice(Some(1), None)(注意,在這種情況下,上/下限可能丟失)。

現在很容易回答你的問題 - 這是一個方法調用,將在運行時進行評估。然而,重要的是要注意整個範圍可能不需要評估!例如:

let nums = seq { 1 .. 10 } |> Seq.take 1 

序列表達將被轉換爲到RangeInt32的呼叫。這隻會返回延遲評估的seq<int>類型的值。撥打take 1只需要第一個元素,因此只需要範圍中的第一個數字並進行評估。

我不認爲你自己的範圍實現可能與標準實現不同,但是你可以提供你的實現作爲對象的成員。然後你可以寫myObj.[1 .. 10](並且結果可以是你想要的任何類型)。爲此,您需要一個實例方法GetSlice,詳細信息請參見discussed here

3

運行時間。作爲編譯的一部分,F#將很少運行您的代碼 - 我能想到的唯一情況是NumericLiteralX模塊中的代碼。此外,在這樣的代碼:

let f n = [1 .. n] 

上編譯甚至不知道在編譯時。當然,作爲實現細節,F#編譯器顯式展開定義,其中兩個邊界都是已知類型的靜態已知值(例如int),但在語義上應該始終與運行時完成的定義相同。

關於你的第二個問題,比什麼快?