タプル
タプルまたはチュープル(tuple)とは、複数の構成要素からなる組を総称する一般概念。
数学や計算機科学などでは通常、順序付けられた対象の並びを表すために用いられる。個別的には、n 個でできた組を英語で「n-tuple」と書き、日本語に訳す場合は通常「n 組」としている。タプルの概念そのものも組と呼ばれる場合がある。なお、 n-tuple は数学のタプルを意味するほか、同様に double、triple などの拡張として倍数詞の表現にも利用される(詳細は「倍#西洋数学における n 倍を表す表現」を参照)。
集合論では n 組 (n-tuple) とは n 個の対象 a1, a2, ..., an の順序づけられた組であり、普通、括弧でくくって (a1, a2, a3, ..., an) のように書かれる。 タプルが順序づけられているということは、
「2つの n 組 (a1, a2, ..., an) と (b1, b2, ..., bn) が等しい」
という表現の意味することが、
「対応する位置の要素がすべて等しいとき」
「 (a1 = b1) ∧ (a2 = b2) ∧ ... ∧ (an = bn) であるとき、かつそのときに限ること」
を意味する。 タプルと直積集合には密接な関係があり、n 組の i 番目の対象が集合 Ai の要素とみなされるならば、n 組は直積集合 A1 × A2 × ... × An の要素である。
2 つの要素 a ∈ A, b ∈ B の順序づけられた組 (a, b) ∈ A × B は特に順序対 (ordered pair) と呼ばれる。 形式上は逆に、この順序対を元とすることによって一般の n 組 (n ≧ 2) を、例えば (a1, a2, a3, ..., an) = (...((a1, a2), a3), ..., an) のようにして構成的に定めることもできる。
タプルは様々な数学概念を定義するためにも利用される。 例えば、有限オートマトンは、入力アルファベットの有限集合 Σ, 状態の有限集合 S, 初期状態 s0 ∈ S, 遷移関数 δ : Σ × S → S, 受理状態の有限集合 F ⊆ S の 5 つ組 (quintuple, 5-tuple) (Σ, S, s0, δ, F) として定められ、有向グラフは、頂点集合 V と辺の集合 A ⊆ V × V の順序対 (V, A) として定められる。
なお数ベクトルも同じように要素の順序づけられた並びとして表されるが、数学の形式上、ある線形空間の要素とみなされるベクトルは実数、複素数など同じ体の要素からなるものである。 対して、タプルは任意の集合の要素を並べただけのずっと一般的な概念であるといえる。
タプルには要素の個数による特殊名が存在する。これらはフランス語に由来するラテン語系の語彙で、少なくとも「クインチュープル」までと「デキュプル」は輸入当時のフランス語から直接受け継いだものである。「 - チュープル」や「 - チュプル」となる個所を「 - タプル」と呼ぶこともある(クインタプル、セクスタプルなど)。また「クオドループル」は「カドラプル」や「クアドラプル」とも言う。
和訳して言うこともある。例としては「シングル」→「一重」「一つ組」、「ダブル」→「二重」「二つ組」、「カドラプル」→「四重」「四つ組」、「デカプル」→「十重」「十個組」など。「シングル」「ダブル」「トリプル」については呼び方がさらにあり、シングルは「独」、ダブルは「ペア」やその和訳である「対」、トリプルは「鼎」が充てられることもある。
型システム的には、代数的データ型でいう直積型そのものであり、C#、C++、Haskell、Kotlin、ML、Python、Scala、TypeScript といった多くのプログラミング言語にタプル型がある。いくつかは (x, y) といったような構文でタプル型の値を直接記述できる。
動的な型付けを持つ言語では、コンテナ型を使うことで済まさせている場合もある。一方でPythonのように、長さを後から変えられないばかりでなく要素を変えることもできないというような、タプル専用のオブジェクトを用意している場合もある。
静的な型付けを持つ言語の場合、リスト型やコンテナ型の要素は、基本的になんらかの「同じ」型でなければならないので、それらの集積型をタプルの目的に流用することは不可能であり、そのためこの節の冒頭のようにタプルないし同等のものをサポートしていることが多い。
(伝統的な)Lispの場合、基本的には線型リストを作るためのデータ構造であるコンスセル(cons cell)を、要素2個のタプル(二ツ組)に流用する。cons, car, cdr というリスト操作用の関数もそのまま流用される。格納するデータの型に制限はない。
car部のデータを取り出すには関数 car を使い、cdr部のデータを取り出すには関数 cdr を使う。
また、
という関数呼び出しは、
という形、すなわち、car部にデータがあり、cdr部が後続のコンスセルになっており、最後のcdr部分を nil という特殊な記号で終端させた二分木を返す。このような形式の二分木は「ちゃんとした」リストになっていると言えることから、「(プロパー)リスト」などという。
Python におけるタプルは、任意の要素数の値をまとめてあたかもひとつの値のように扱う機能である。
タプルでは要素の型 (数値型、文字列型など)の同一性は不問であり、たとえば ('A', 1) という文字列と整数をひと塊として変数に代入できる。
Pythonはゼロまたはひとつの要素となるタプルも認めており、とくに1要素のタプルはプログラミング言語としては珍しい。普通、そのようなものは計算の優先順位を変更するため、または1引数関数の引数を括るための括弧と区別できないからである。Pythonの場合、要素に続けてカンマを置くことで識別する。カンマを忘れるとタプルとして認識できなくなってしまうということでもある。
タプルは関数の返り値として使うこともできる。これによって、複数の値を返す関数を実現することができる。
また、タプルは下記のようにして個別の要素を分離する。
ML系の関数型言語にほぼ共通して言えることとして、再帰的なデータ型であるリストとは異なり、タプルはそうでない点がある。また、リストの要素は単一の型のみを許容するのに対し、タプルの要素は型を問わない。これもデータ構造が再帰的か否かという点に由来するものである。また、要素へのアクセスはパターンマッチングか、先頭要素とその次の要素程度までを求める関数しかない。再帰的に定義されていないため、再帰関数で手繰ることも難しい(リストなら先頭と残りに分離することで容易に行える)。にもかかわらず、多くの関数型言語は60前後の要素まで許容されている。
Haskellでは、Pythonに類似した方法で利用できる部分もある。Pythonなどに影響を与えた側なので当然といえば当然である。
アクセス関数としては、第1要素を取得するfstと、第2要素を取得するsndがある。
Haskellでは、2要素のタプルはデータ構築子 (,) で定義される。3要素なら (,,) で、最大の要素数は64であるため、これはカンマが63個並ぶことになる。以下はどちらも同じタプルが生成される。
もちろんセクション(演算子の部分適用)も可能である。
セクションなどでは、要素数に応じた構築子を使わなければならない。たとえば要素数が3ならば
ユーティリティ関数としてcurryとuncurryが定義されている。いずれも2-tupleしか受け付けない。
C#言語におけるタプル(System.Tupleクラス)は.NET Framework 4.0からサポートされた総称型のコンテナのひとつ。CLIで定義されたクラスであるためVisual Basic .NETでも同様に使用可能である。
それぞれの値の取り出しは、Item1, Item2, ... にアクセスすることで行える。Pythonと違い、Tuple型で返したからといって複数の戻り値を返す関数とはならない。
他にも同様の総称型を持つ言語では、同様にしてタプルを使えるかもしれない。
なお、C#7.0からサポートされたタプル構文では、それ以前に存在していたSystem.Tupleクラス(参照型)ではなく、新たに実装されたSystem.ValueTuple構造体(値型)が使用されるようになっている。これにより使用時のインスタンス化が不要となった。
その他、各タプルフィールドへの命名(名前付きタプル)、分解構文(Deconstruct())を介した複数の戻り値の受け取りや、タプルそのものを直接ジェネリックの型引数として宣言することが可能となるなど、言語仕様の一部として統合された形で扱えるようになった。
TypeScript 1.3 から対応した。
関係データベースの理論である関係モデルでは、タプル(組)とはある関係(リレーション)を表(テーブル) として表したときの1つの行にあたり、形式的には、上述のタプルと同様に属性名を添字とした属性の型の直積集合の要素として表される。