2013-02-11 45 views
8
type foo = A of int * int | B of (int * int) 

int * int(int * int)之間有什麼區別?我看到的唯一區別是模式匹配:OCaml中的int * int vs(int * int)和類型

let test_foo = function 
    | A (f, s) -> (f, s) 
    | B b -> b 

它只是一個語法糖嗎?你如何選擇使用哪一個?這兩種形式之間有什麼表現差異?

+0

很好的問題。 – didierc 2013-02-11 20:33:52

回答

7

是的,有一個性能差異:

在存儲器A (23, 42)將包含標籤標識它作爲一個A和兩個整數23與42 B (23, 42)將包含標籤標識它作爲一個B和指向包含整數2342的元組。因此,在創建B時會有一個額外的內存分配,並且在訪問B內部的各個值時會有一個額外的間接級別。因此,如果您實際上並未將構造函數參數用作元組,則使用A將比使用B花費更少的開銷。

在另一方面你test_foo功能將創建一個新的記錄每次調用與A值的時間,但是當它被稱爲一個B值將簡單的返回已經存在於內存中的元組。因此test_foo對於BA更便宜。因此,如果您將構造函數的參數用作元組,並且您將多次使用相同的值,則使用B將會更便宜。

所以如果你打算使用構造函數參數作爲元組,那麼使用構造函數來獲取元組是有意義的,因爲你可以通過使用少量代碼的模式匹配來獲得元組,並且因爲它可以避免必須多次創建來自相同值的元組。在所有其他情況下,不使用元組更好,因爲它涉及較少的內存分配和較少的間接。

+0

所以,沒有新的元組創建就不可能從'A'中提取信息,對吧? – Stas 2013-02-11 19:28:08

+0

@Stas這取決於你的意思是「提取信息」。無法創建包含「A」數據的元組而不創建新的元組。但是,無需創建元組就可以用'A'的數據做一些事情。例如,像'match foo with A(x,y) - > x + y'這樣的東西不會創建一個元組,並且會比使用'B'的等價代碼快。 – sepp2k 2013-02-11 19:32:11

+0

我明白了。謝謝!我認爲元組需要匹配'A(x,y)'。 – Stas 2013-02-11 19:52:37

0

它們是兩種不同的類型。該語法的解釋在*運算符處不明確。它可被還原成以下形式:

,其中「*」是OCaml中 或 int * inttype關鍵字相關聯

type x = Y * Z其中*是在構造了一個元組操作者的能力使用

默認優先級將其轉換爲前者。通過圍繞(int * int)放置括號,可以覆蓋默認優先級並強制執行後面的解釋。

2

如前所述,A的構造函數需要兩個int,而B的構造函數需要一個有序對。

所以你可以寫

let bar = A (1, 2) 

let bar = B (1, 2) 

let bar = (1, 2) 
let baz = B bar 

,但你不能寫

let bar = (1, 2) 
let baz = A bar 

此外,在你的模式匹配,你仍然可以B的內容相匹配的兩個int,但不能A的內容相匹配的綁定到一個有序對

let test_foo = function 
    | A a -> a (* wrong *) 
    | B (f, s) -> (f, s) (* ok *) 
0

這是棘手的事情在一個價值OCaml語法 - 即使它看起來像使用元組數據類型(A of int * int)聲明構造函數,並且即使在使用構造函數時,它看起來像是給它一個元組(A (2,3)),但實際上並非如此發生什麼事。

如果實際構造一個元組值並嘗試將其傳遞給構造函數,它將不會編譯 - let x = (2,3) in A x。相反,構造函數定義中的*和構造函數use表達式中的(,)只是多個參數的構造函數的語法。語法模仿具有元組參數的構造函數,但實際上是分開的。如果你想用一個元組參數實際構造一個構造函數,額外的括號是必須的。