web-dev-qa-db-ja.com

OCaml:タプルのn番目の要素を抽出しますか?

リストの場合、パターンマッチングを実行してn番目の要素まで繰り返すことができますが、タプルの場合、n番目の要素をどのように取得しますか?

13
user3340037

OCamlタプルの長さは型の一部であり、コンパイル時に既知(そして固定)であるため、タプルでの単純なパターンマッチングによってn番目の項目を取得します。同じ理由で、「任意の長さのタプル」のn番目の要素を抽出する問題は実際には起こりません-このような「タプル」 OCamlの型システムでは表現できません。

タプルを投影する必要があるたびにパターンを書きたいとは思わないかもしれませんが、i- th要素をj- Tupleから可能な限り抽出する関数get_1_1...get_i_j...を生成できます。コードで発生するijの組み合わせ、例えば.

let get_1_1 (a) = a
let get_1_2 (a,_) = a
let get_2_2 (_,a) = a
let get_1_3 (a,_,_) = a
let get_2_3 (_,a,_) = a
...

必ずしもきれいではありませんが、可能です。

:以前、OCamlのタプルは最大255の長さであり、可能なすべてのタプルプロジェクションを一度に生成できると私は主張していました。 @Virgileがコメントで指摘したように、これは誤りです-タプルは巨大になる可能性があります。つまり、all可能なタプル投影関数を事前に生成することは実際的ではないため、コードで発生する制限「 "上記。

8
user2361830

TL; DR;n-aのt-の要素に直接アクセスしようとするのをやめますランダムアクセスを許可するため、レコードまたは配列をアップして使用します。

n-番目の要素は、npackingt-upleを使用して値の分解を行うことができます。let構文を使用するか、 match構文または関数定義:

let ivuple = (5, 2, 1, 1)

let squared_sum_let =
  let (a,b,c,d) = ivuple in
  a*a + b*b + c*c + d*d

let squared_sum_match =
  match ivuple with (a,b,c,d) -> a*a + b*b + c*c + d*d

let squared_sum_fun (a,b,c,d) =
  a*a + b*b + c*c + d*d

match- constructには、ここでlet- constructよりも美徳はありません。完全を期すために含まれているだけです。

t-uplesは使用しないでください。

型を表すためにt-uplesを使用することが適切な場合は、ごくわずかです。ほとんどの場合、型を定義するのが面倒なので、t-upleを選択し、n-thのフィールドにアクセスする問題を解釈する必要があります- t-upleまたはt-upleのフィールドを反復適切なタイプに切り替える時が来たの重大なシグナルとして。

t-uplesには2つの自然な置き換えがあります:recordsおよびarrays。

いつレコードを使用するか

レコードはt-upleとしてラベル付けされたエントリと見なすことができます。そのため、直接アクセスしたい場合、これらは間違いなくt-uplesの最も自然な置き換えです。 。

type ivuple = {
  a: int;
  b: int;
  c: int;
  d: int;
}

次に、x.aと書き込んで、タイプaの値xのフィールドivupleに直接アクセスします。 let y = { x with d = 0 }のように、レコードは変更して簡単にコピーできることに注意してください。レコードのフィールドを反復する自然な方法はありません。これは、ほとんどの場合、レコードが均一である必要がないためです。

配列を使用する場合

大規模で均質な値のコレクションは、配列によって適切に表現されます。これにより、直接アクセス、反復、および折りたたみが可能になります。不便なのは、配列のサイズがその型の一部ではないことですが、固定サイズの配列の場合、プライベート型または抽象型を導入するだけで簡単に回避できます。この手法の例については、「OCamlコンパイラがベクターの長さをチェックする」という質問に対して my answer で説明しました。

フロートボクシングに関する注意

t-uples、レコードfloatsのみを含む、および配列でフロートを使用する場合、これらはボックス化されません。したがって、数値計算であるタイプから別のタイプに変更するときに、パフォーマンスの変更に気付くことはありません。


-the TeXbookを参照してください。 ²ラージスタートは4近くです。

このような関数をOCamlで一般的に記述することはできません。これを確認する1つの方法は、関数のタイプを考えることです。 2つの問題があります。まず、タプルの各サイズは異なるタイプです。したがって、異なるサイズのタプルの要素にアクセスする関数を作成することはできません。 2番目の問題は、タプルの異なる要素が異なるタイプを持つ可能性があることです。リストにはこれらの問題はありません。そのため、List.nth

要素がすべて同じ型である固定サイズのタプルを使用する場合は、@ user2361830で示されている関数を記述できます。

更新

インデックスでアクセスしたい同じタイプの値のコレクションが本当にある場合は、おそらく配列を使用する必要があります。

2