type foo = A of int * int | B of (int * int)
int * int
と(int * int)
そこの違いは何ですか?私が見る唯一の違いは、パターンマッチングにあります。
let test_foo = function
| A (f, s) -> (f, s)
| B b -> b
それは単なる構文糖衣ですか?どちらを使用するかをどのように選択しますか?これら2つの形式の間にパフォーマンスの違いはありますか?
type foo = A of int * int | B of (int * int)
int * int
と(int * int)
そこの違いは何ですか?私が見る唯一の違いは、パターンマッチングにあります。
let test_foo = function
| A (f, s) -> (f, s)
| B b -> b
それは単なる構文糖衣ですか?どちらを使用するかをどのように選択しますか?これら2つの形式の間にパフォーマンスの違いはありますか?
はい、パフォーマンスに違いがあります。
メモリ内A (23, 42)
には、それをanとして識別するタグA
と、2つの整数23および42B (23, 42)
が含まれます。これには、それをaとして識別するタグと、整数および。B
を含むタプルへのポインタが含まれます。したがって、を作成するときに1つの追加のメモリ割り当てがあり、内の個々の値にアクセスするときに1つの追加レベルの間接参照があります。したがって、コンストラクター引数をタプルとして実際に使用しない場合、を使用すると、を使用するよりもオーバーヘッドが少なくなります。23
42
B
B
A
B
一方、test_foo
関数は値を指定して呼び出されるたびに新しいタプルを作成しますが、A
値を指定して呼び出されると、B
メモリにすでに存在するタプルを返すだけです。したがって、の場合よりもtest_foo
安価な操作です。したがって、コンストラクターの引数をタプルとして使用し、同じ値に対して複数回使用する場合は、使用する方が安価になります。B
A
B
したがって、コンストラクター引数をタプルとして使用する場合は、より少ないコードでパターンマッチングを使用してタプルを取得でき、タプルを作成する必要がないため、タプルを取得するコンストラクターを使用するのが理にかなっています。同じ値を複数回。他のすべての場合、タプルを使用しない方が、メモリ割り当てと間接参照が少なくなるため、推奨されます。
As already said, the constructor of A
takes two int
, whereas the constructor of B
takes an ordered pair.
so you can write
let bar = A (1, 2)
or
let bar = B (1, 2)
or
let bar = (1, 2)
let baz = B bar
but you cannot write
let bar = (1, 2)
let baz = A bar
Moreover, in your pattern matching, you can still match the content of B as two int, but you cannot match the content of A as value bound to an ordered pair
let test_foo = function
| A a -> a (* wrong *)
| B (f, s) -> (f, s) (* ok *)
それらは2つの異なるタイプです。この構文の解釈は、*
オペレーターではあいまいです。次の形式に縮小できます。
type x = Y * Z
type
'*'がOCamlのキーワードに
関連付けられているかint * int
、*
タプルを作成する演算子の能力で使用されている
デフォルトの優先順位は前者になります。括弧を囲むことにより(int * int)
、デフォルトの優先順位をオーバーライドし、後者の解釈を強制します。
これはOCaml構文のトリッキーなことの1つです-タプルデータ型(A of int * int
)でコンストラクターを宣言しているように見えても、コンストラクターを使用するとタプルを与えているように見えます()A (2,3)
)、それは実際に起こっていることではありません。
実際にタプル値を作成してコンストラクターに渡そうとすると、コンパイルされません- let x = (2,3) in A x
。むしろ、*
コンストラクター定義のinとコンストラクターuse式のは、複数の引数(,)
のコンストラクターの構文にすぎません。構文は、タプル引数を持つコンストラクターの構文を模倣していますが、実際には別個のものです。単一のタプル引数を使用してコンストラクターを実際に作成する場合は、追加の括弧が必要です。