次: , 前: List Elements, 上: Lists


5.5 コンスセルとリストの構築

リストはLispの中核なので、多くの関数はリストを構築します。 consは基本的なリスト構築関数です。 しかし、Emacsのソースコードでは、consよりlistを 多用していることは興味深いことです。

— 機能: cons object1 object2

この関数は、新たなリスト構造を構築するために使う基本関数。 object1carobject2cdrとする 新たなコンスセルを作成し、このコンスセルを返す。 引数object1object2はどんなLispオブジェクトでもよいが、 ほとんどの場合、object2はリストである。

          (cons 1 '(2))
               => (1 2)
          (cons 1 '())
               => (1)
          (cons 1 2)
               => (1 . 2)
     

consは、リストの先頭に要素を1つ追加するために しばしば使われる。 これを要素をリストにコンスするという。 たとえば、つぎのとおり。

          (setq list (cons newelt list))
     

この例におけるlistという名前の変数と 以下に述べるlistという名前の関数とは衝突しない。 任意のシンボルはどちらの目的にも使える。

— 機能: list &rest objects

この関数は、objectsを要素とするリストを作成する。 結果のリストはつねにnil終端になる。 objectsを指定しないと空リストを返す。

          (list 1 2 3 4 5)
               => (1 2 3 4 5)
          (list 1 2 '(3 4 5) 'foo)
               => (1 2 (3 4 5) foo)
          (list)
               => nil
     
— 機能: make-list length object

この関数は、すべての要素が同一の値objectであり 長さがlengthのリストを作成する。 make-stringと比較してほしい(see Creating Strings)。

          (make-list 3 'pigs)
               => (pigs pigs pigs)
          (make-list 0 'pigs)
               => nil
     
— 機能: append &rest sequences

この関数はsequencesのすべての要素から成るリストを返す。 sequencesは、リスト、ベクトル、ブールベクトル、文字列のいずれかであるが、 普通、最後の要素はリストである。 最後の引数を除いてすべての引数をコピーするので、どの引数も変更しない (コピーせずにリストを繋ぐ方法については、 Rearrangementnconcを参照。)

一般には、appendの最後の引数はどんなLispオブジェクトでもよい。 最後の引数をコピーしたり変換したりしない。 それは、新たなリストの最後のコンスセルのcdrになる。 最後の引数がそれ自体リストであれば、それらの要素は、実質的には、 結果のリストの要素になる。 最後の要素がリストでなければ、結果は『ドット対』になる。 なぜなら、結果の最後のcdrは、 真のリストに必要とされるnilではないからである。

関数appendは、引数として整数も受け付ける。 整数を10進の表示表現の文字列に変換してから、 その文字列を整数のかわりに使う。 この機能を使わないでほしい。 削除する予定である。 読者がこの機能を使っていたら、今すぐプログラムを直すこと! 整数をこのような10進数に変換する正しい方法は、 format(see Formatting Strings)や number-to-string(see String Conversion)を使うことである。

appendの使用例をつぎに示します。

     (setq trees '(pine oak))
          => (pine oak)
     (setq more-trees (append '(maple birch) trees))
          => (maple birch pine oak)
     
     trees
          => (pine oak)
     more-trees
          => (maple birch pine oak)
     (eq trees (cdr (cdr more-trees)))
          => t

箱表示を見ればappendの動作を理解できるでしょう。 変数treesにリスト(pine oak)を設定し、ついで、 変数more-treesにはリスト(maple birch pine oak)を設定します。 しかし、変数treesはもとのリストを指し続けます。

     more-trees                trees
     |                           |
     |     --- ---      --- ---   -> --- ---      --- ---
      --> |   |   |--> |   |   |--> |   |   |--> |   |   |--> nil
           --- ---      --- ---      --- ---      --- ---
            |            |            |            |
            |            |            |            |
             --> maple    -->birch     --> pine     --> oak

空シーケンスはappendが返す値にはまったく寄与しません。 この結果、最後のnil引数は直前の引数をコピーするように強制します。

     trees
          => (pine oak)
     (setq wood (append trees nil))
          => (pine oak)
     wood
          => (pine oak)
     (eq wood trees)
          => nil

この方法は、関数copy-sequenceを導入するまでは、 リストをコピーする普通の方法でした。 See Sequences Arrays Vectors

appendの引数にベクトルと文字列を使った例をつぎに示します。

     (append [a b] "cd" nil)
          => (a b 99 100)

apply(see Calling Functions)の助けを借りれば、 リストのリストの中にあるすべてのリストを連結できます。

     (apply 'append '((a b c) nil (x y z) nil))
          => (a b c x y z)

sequencesをまったく指定しないとnilを返します。

     (append)
          => nil

最後の引数がリストではない例をいくつか示します。

     (append '(x y) 'z)
          => (x y . z)
     (append '(x y) [z])
          => (x y . [z])

最後の引数がリストではなくシーケンスである2番目の例は、 シーケンスの要素が結果のリストの要素にはならないことを示しています。 そのかわりに、最後の引数がリストでない場合と同様に、 シーケンスが最後のcdrになります。

— 機能: reverse list

この関数は、listの要素を逆順にした新たなリストを作成する。 もとの引数listは変更しない

          (setq x '(1 2 3 4))
               => (1 2 3 4)
          (reverse x)
               => (4 3 2 1)
          x
               => (1 2 3 4)