コンピュータプログラミングでは、cons( / ˈ k ɒ n z /または/ ˈ k ɒ n s / ) は、Lispプログラミング言語のほとんどの方言における基本的な関数です。は、2 つの値または 2 つの値へのポインタを保持するメモリ オブジェクトを構築します。これらのオブジェクトは、(cons) セル、cons、非原子S 式("NATS")、または (cons)ペアと呼ばれます。Lisp の専門用語では、式 "to cons x onto y " は、を使用して新しいオブジェクトを構築することを意味します。結果として得られるペアには、(最初の要素、またはレジスタのアドレス部分の内容)と呼ばれる左半分と、(2 番目の要素、またはレジスタのデクリメント部分の内容)と呼ばれる右半分があります。cons(cons xy)carcdr
これは、引数を与えて新しいオブジェクトを作成するオブジェクト指向のコンストラクタの概念と緩やかに関連しており、より密接には代数的データ型システムのコンストラクタ関数に関連している。
「cons」という単語や「to cons onto」のような表現は、より一般的な関数型プログラミングの専門用語の一部でもあります。特にリスト処理の文脈では、同様の目的を持つ演算子が「cons」と発音されることがあります。(良い例としては、 ML、Scala、F#、Lean、Rocq、Elm::の演算子や、Haskellの演算子(リストの先頭に要素を追加する)が挙げられます。):
consセルは順序付きデータのペアを保持するために使用できますが、より一般的には、リストや二分木などのより複雑な複合データ構造を構築するために使用されます。
例えば、Lisp式は、左半分(いわゆるフィールド)に1、右半分(フィールド)に2を持つセルを構築します。Lisp表記では、値は次のようになります。(cons12)carcdr(cons12)
(1.2)
1と2の間にドットがあることに注目してください。これは、S式が「リスト」ではなく「ドット付きペア」(いわゆる「consペア」)であることを示しています。

cons:( cons 42 ( cons 69 ( cons 613 nil )))list:(リスト42 69 613 )Lispでは、リストはconsペアの上に実装されています。より具体的に言うと、Lispにおけるリスト構造は次のいずれかです。
()、通常 と呼ばれる特別なオブジェクトですnil。carリストの最初の要素であり、残りの要素を含むリストcdrであるconsセル。これは、単純な単方向連結リスト構造の基礎を形成し、その内容はcons、、、carおよびを使用して操作できますcdr。 は、nilcons ペアではない唯一のリストであることに注意してください。例として、要素が 1、2、および 3 であるリストを考えてみましょう。このようなリストは、次の 3 つのステップで作成できます。
nil空のリストにこれは、次の単一の式と同等です。
( cons 1 ( cons 2 ( cons 3 nil )))または略記:
(リスト1 2 3 )結果として得られる値はリストです。
(1 . (2 . (3 . 0)))
つまり
*--*--*--なし | | | 1 2 3
一般的には次のように略されます。
(1 2 3)
したがって、cons既存の連結リストの先頭に要素を1つ追加するために使用できます。たとえば、xが上記で定義したリストである場合、次のリストが生成されます。(cons5x)
(5 1 2 3)
もう一つ便利なリスト操作は、既存の2つのリストを連結する(つまり、2つのリストを1つのリストに結合する)`append`です。
葉にのみデータを格納する二分木も、 を使って簡単に構築できますcons。例えば、次のコードのようにです。
( cons ( cons 1 2 ) ( cons 3 4 ))ツリー内の結果:
((1 . 2) . (3 . 4))
つまり
* / \ * * / \ / \ 1 2 3 4
厳密に言えば、前の例のリスト(1 2 3)も二分木であり、特にバランスの悪い二分木です。これを確認するには、図を並べ替えるだけで済みます。
*--*--*--なし | | | 1 2 3
以下の同等の形式に置き換えます。
* / \ 1 * / \ 2 * / \ 3対0
Consは、命令型プログラミング言語で使用されるような破壊的な操作とは対照的に、メモリ割り当ての一般的なプロセスを指す場合があります。例:
副作用を組み込むことで、コードの速度を少し向上させました。以前は、冗長なcons処理をしていたためです。
Lispには第一級関数があるため、consセルを含むすべてのデータ構造は関数を使用して実装できます。たとえば、Schemeでは次のようになります。
( define ( cons x y ) ( lambda ( m ) ( m x y ))) ( define ( car z ) ( z ( lambda ( p q ) p ))) ( define ( cdr z ) ( z ( lambda ( p q ) q )))この手法はチャーチ符号化として知られています。これは、関数を「consセル」として使用して、 cons、car、およびcdr演算を再実装します。チャーチ符号化は、Schemeと密接に関連する抽象的な理論的計算モデルである純粋ラムダ計算において、データ構造を定義する一般的な方法です。
この実装は学術的には興味深いものの、consセルを他のSchemeの手続きと区別できなくしてしまうだけでなく、不必要な計算効率の低下を招くため、実用的ではない。
しかし、同じ種類のエンコーディングは、バリアントを持つより複雑な代数的データ型にも使用でき、他の種類のエンコーディングよりも効率的になる場合もあります。[ 1 ]また、このエンコーディングは、 Java のようにバリアントを持たない静的型付け言語で、ラムダの代わりにインターフェースを使用して実装できるという利点もあります。