コンピュータプログラミングにおいて、cons( / ˈ k ɒ n z /または/ ˈ k ɒ n s / ) は、Lispプログラミング言語のほとんどの方言における基本的な関数です。 は、2 つの値または 2 つの値へのポインタを保持するメモリオブジェクトを構築します。これらのオブジェクトは、(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の演算子が挙げられます。):
使用
コンスセルは順序付けられたデータのペアを保持するために使用できますが、より複雑な複合データ構造、特にリストやバイナリツリーを構築するために使用されることが一般的です。
順序付きペア
例えば、Lisp式は、左半分(いわゆるフィールド)に1、右半分(フィールド)に2を保持するセルを構築します。Lisp記法では、値は次のようになります (cons12)carcdr(cons12)
(1.2)
1と2の間にドットがあることに注意してください。これは、S式が「リスト」ではなく「ドットペア」(いわゆる「コンスペア」)であることを示しています
リスト

consます(コンス42 (コンス69 (コンス613ゼロ)))list:(リスト42 69 613 )Lispでは、リストはコンスペアの上に実装されます。より具体的には、Lispにおけるリスト構造は次のいずれかです。
- 空のリスト
()。これは通常 と呼ばれる特殊なオブジェクトですnil。 carリストの最初の要素であり、残りの要素を含むリストcdrであるコンス セル。
これは、、、で内容を操作できる、単純な片方向リンクリスト構造の基礎となります。 は、consペアではない唯一のリストであることに注意してください。例として、要素が1、2、3のリストを考えてみましょう。このようなリストは、次の3つのステップで作成できます。 conscarcdrnil
- 3を
nil空のリストにコンスする - 結果に欠点2
- 結果に欠点1
これは次の単一の式と同等です。
(コンス1 (コンス2 (コンス3 nil )))またはその略語:
(リスト1 2 3 )結果の値は次のリストになります。
(1 . (2 . (3 . ゼロ)))
すなわち
*--*--*--nil | | | 1 2 3
一般的には次のように略されます
(1 2 3)
したがって、はcons既存の連結リストの先頭に1つの要素を追加するために使用できます。例えば、xが上で定義したリストである場合、次のリストが生成されます (cons5x)
(5 1 2 3)
もう 1 つの便利なリスト プロシージャはappendです。これは、既存の 2 つのリストを連結します(つまり、2 つのリストを 1 つのリストに結合します)。
木
葉にのみデータを格納する二分木も、を使って簡単に構築できますcons。例えば、次のコードです
(コンス(コンス1 2 ) (コンス3 4 ))ツリーの結果は次のようになります。
((1.2).(3.4))
すなわち
* / \ * * / \ / \ 1 2 3 4
技術的には、前の例のリスト (1 2 3) も二分木ですが、特に不均衡な二分木です。これを確認するには、図を次のように並べ替えてください。
*--*--*--nil | | | 1 2 3
次のように等価になります
* / \ 1 * / \ 2 * / \ 3 0
会話での使用
consは、命令型プログラミング言語で使用されるような破壊的な操作とは対照的に、メモリ割り当ての一般的なプロセスを指す場合があります。例:
ばかばかしいほど cons する代わりに副作用を入れることで、コードを少し高速化しました。
関数型実装
Lispには第一級関数があるため、コンスセルを含むすべてのデータ構造は関数を使って実装できます。例えば、Schemeでは:
(定義( cons x y ) (ラムダ( m ) ( m x y ))) (定義( car z ) ( z (ラムダ( p q ) p ))) (定義( cdr z ) ( z (ラムダ( p q ) q )))この手法はチャーチ符号化として知られています。これは、関数を「コンスセル」として用いて、cons、car、cdr演算を再実装します。チャーチ符号化は、Schemeと密接に関連する抽象的かつ理論的な計算モデルである純粋ラムダ計算において、データ構造を定義する際によく用いられる方法です。
この実装は学術的には興味深いものですが、コンス セルを他の Scheme プロシージャと区別できなくなり、不必要な計算の非効率性も生じるため、実用的ではありません。
しかし、同じ種類のエンコーディングは、バリアントを持つより複雑な代数データ型にも使用でき、他の種類のエンコーディングよりも効率的であることが判明する場合があります。[ 1 ]このエンコーディングには、 Java などのバリアントを持たない静的型付け言語で、ラムダの代わりにインターフェースを使用して実装できるという利点もあります。
参照
参考文献
- ^ 「データ型とパターンを関数に変換することによる効率的な解釈」(PDF) 。 2010年3月31日時点のオリジナル(PDF)からアーカイブ。 2009年3月1日閲覧。
外部リンク
- SDRAW、Common Lispの 描画コードでコンスセル構造を描画します。David S. Touretzky提供