例えば、リスト (rose violet buttercup) には ‘rose’、‘violet’、‘buttercup’ という3つの要素があります。コンピュータ内では、‘rose’ の電子アドレスは、consセルと呼ばれるコンピュータメモリのセグメントに記録されています(関数 cons
が実際に作成するのがこれであるためです)。そのconsセルは、さらに2つ目のconsセルのアドレスも保持しており、その CAR はアトム ‘violet’
となっています。そして、そのアドレス(‘violet’
がどこにあるかを示すもの)は、アトム ‘buttercup’
のアドレスを保持する3つ目のconsセルのアドレスと共に保存されています。
これは実際よりも複雑に聞こえますし、図で見たほうがわかりやすいです:
この図において、各ボックスはLispオブジェクト(通常はメモリアドレスの形式)を格納するコンピュータメモリ上のワードを表している。ボックス、すなわちアドレスはペアになっている。各矢印は、そのアドレスが指す先、すなわちアトムか、あるいは別のアドレスペアのいずれかを示している。最初のボックスは‘rose’の電子アドレスであり、矢印は‘rose’を指している。2番目のボックスは次のボックスペアのアドレスであり、その前半部分は‘violet’のアドレス、後半部分は次のペアのアドレスとなっている。一番最後のボックスはシンボルnilを指しており、これがリストの終端を示している。
変数に setq
のような演算を用いてリストを代入すると、変数には最初のボックスのアドレスが格納されます。したがって、式の評価は
(setq bouquet '(rose violet buttercup))
次のような状況になります:
この例では、記号 bouquet が最初の一組のボックスのアドレスを保持しています。
同じリストを、次のような別の形式のボックス表記で示すこともできます。
(シンボルはアドレスのペア以上の要素から構成されるが、シンボルの構造はアドレスによって成り立っている。実際、シンボル bouquet はアドレスボックスの集合から成り、その一つは印刷語 ‘bouquet’
のアドレスであり、二つ目は(もしあれば)シンボルに付随する関数定義のアドレスであり、三つ目はリスト (rose
violet buttercup)
の最初のアドレスボックスのペアのアドレスであり、以下同様である。ここでは、シンボルの三番目のアドレスボックスが、リストの最初のアドレスボックスのペアを指していることを示している。)
シンボルがリストのCDRに設定されている場合、リスト自体は変更されず、単にそのシンボルがリストのより後方のアドレスを持つことになります。(専門用語では、CARとCDRは「非破壊的」と呼ばれます。)したがって、以下の式の評価は
(setq flowers (cdr bouquet))
以下を生成します:
flowersの値は(violet
buttercup)であり、すなわち、記号flowersはアドレスボックスのペアのアドレスを保持しており、その1つ目はvioletのアドレスを、2つ目はbuttercupのアドレスを保持している。
A pair of address-boxes is called a cons cell or dotted pair. See Cons Cell and List Types in The GNU Emacs Lisp Reference Manual, and Dotted Pair Notation in The GNU Emacs Lisp Reference Manual, for more information about cons cells and dotted pairs.
関数 cons
は、上記に示すような一連のアドレスの先頭に、新たなアドレスのペアを追加します。例えば、次の式を評価すると、
(setq bouquet (cons 'lily bouquet))
生成する:
しかし、これはシンボル flowers の値を変えるものではなく、以下を評価すればわかる通り、
(eq (cdr (cdr bouquet)) flowers)
true の場合に t を返します。
リセットされるまで、flowersは依然として値(violet
buttercup)を保持している。つまり、第1アドレスがvioletであるコンスセルのアドレスを保持していることになる。また、これにより既存のコンスセルが変更されることはなく、すべてそのまま存在し続ける。
このように、LispでリストのCDRを取得するには、単に系列内の次のコンスセルのアドレスを取得すればよい。リストのCARを取得するには、リストの最初の要素のアドレスを取得すればよい。リストに新しい要素をcons追加するには、リストの先頭に新しいコンスセルを追加すればよい。たったこれだけだ!Lispの根底にある構造は、見事にシンプルだ!
では、一連のconsセルにおける最後のアドレスは何を指すのでしょうか?それは空リスト、すなわちnilのアドレスです。
まとめると、Lispの変数に値が代入される際、その変数が参照するリストのアドレスが併せて提供されます。