R6RS:翻訳:R6RS:11.9 Pairs and lists

R6RS:翻訳:R6RS:11.9 Pairs and lists

11.9 対とリスト

は car と cdr (この名前は歴史的理由による)と呼ばれるふたつのフィールドを持つ合成構造である。対は cons 手続きで作成され、 car と cdr のフィールドは car 手続きと cdr 手続きでアクセスされる。

対はまず、リストを表現するのに使うことができる。リストは空リストか cdr がリストである対として再帰的に定義することができる。より精確に言うと、リストの集合は次を満たすような最小の集合 X として定義される。

リストの後続の対の car フィールドのオブジェクトはそのリストの要素である。例えば、 2 要素のリストは、その car が最初の要素であり、 cdr は対であり、その car は 2 番目の要素であり、その cdr は空リストである。リストの長さはその要素数である。これは対の個数と同一である。

空リストはそれ自体の型を持つ特別なオブジェクトである。空リストは対ではない。空リストは要素を持たず、長さは 0 である。

: 上の定義はリストはすべて有限の長さを持ち空リストで終端されることを暗示している。

空リストで終端されない対の連鎖を非真正リストと呼ぶ。非真正リストはリストでないことに注意。リスト表記とドット表記を組み合わせて非真正リストを表すことができる。

(a b c . d)

は次と等価である。

(a . (b . (c . d)))

与えられた対がリストであるかどうかはその cdr フィールドに何が格納されているかに依存している。

[procedure] (pair? obj)

obj が対であれば #t を返し、そうでなければ #f を返す。

(pair? ’(a . b))                ⇒  #t
(pair? ’(a b c))                ⇒  #t
(pair? ’())                     ⇒  #f
(pair? ’#(a b))                 ⇒  #f

[procedure] (cons obj1 obj2)

car が obj1 であり、 cdr が obj2 である対を新たに割り当てて返す。この対は(eqv? の意味で)既存のオブジェクトと異なることが保証されている。

(cons ’a ’())                   ⇒  (a)
(cons ’(a) ’(b c d))            ⇒  ((a) b c d)
(cons "a" ’(b c))               ⇒  ("a" b c)
(cons ’a 3)                     ⇒  (a . 3)
(cons ’(a b) ’c)                ⇒  ((a b) . c)

[procedure] (car pair)

pair の car フィールドの内容を返す。

(car ’(a b c))                  ⇒  a
(car ’((a) b c d))              ⇒  (a)
(car ’(1 . 2))                  ⇒  1
(car ’())                 &assertion exception

[procedure] (cdr pair)

(cdr pair) procedure

pair の cdr フィールドの内容を返す。

(cdr ’((a) b c d))              ⇒  (b c d)
(cdr ’(1 . 2))                  ⇒  2
(cdr ’())                 &assertion exception

[procedure] (caar pair)

[procedure] (caar pair)

 …

[procedure] (caar pair)

[procedure] (caar pair)

これらの手続きは car と cdr の組み合わせである。例えば caddr は次のように定義できる。

(define caddr (lambda (x) (car (cdr (cdr x))))).

深さ 4 までの任意の組み合わせが提供されている。これらの手続きはすべてで 28 個ある。

[procedure] (null? obj)

obj が空リストであれば #t を返し、そうでなければ #f を返す。

[procedure] (list? obj)

obj がリストであれば #t を返し、そうでなければ #f を返す。定義により、リストはすべて有限の長さを持つ対の連鎖であり、空リストで終端されたものである。

(list? ’(a b c))             ⇒  #t
(list? ’())                  ⇒  #t
(list? ’(a . b))             ⇒  #f

[procedure] (list obj ...)

引き数から成る新たに割り当てられたリストを返す。

(list ’a (+ 3 4) ’c)                    ⇒  (a 7 c)
(list)                                  ⇒  ()

[procedure] (length list)

list の長さを返す。

(length ’(a b c))                       ⇒  3
(length ’(a (b) (c d e)))               ⇒  3
(length ’())                            ⇒  0

[procedure] (append list ... obj)

最初のリストの要素に他のリストの要素が続き、 obj を最後の cdr とする(場合によっては)非真正リストを返す。 obj がリストでない場合には非真正リストを返す。

(append ’(x) ’(y))                      ⇒  (x y)
(append ’(a) ’(b c d))                  ⇒  (a b c d)
(append ’(a (b)) ’((c)))                ⇒  (a (b) (c))
(append ’(a b) ’(c . d))                ⇒  (a b c . d)
(append ’() ’a)                         ⇒  a

append が空でない対の連鎖を構築した場合、対は常に新たに割り当てられる。対が割り当てられなかった場合には obj が返される。

[procedure] (reverse list)

list の要素を逆順にしたリストを新たに割り当てて返す。

(reverse ’(a b c))                      ⇒  (c b a)
(reverse ’(a (b c) d (e (f))))  
                ⇒  ((e (f)) d (b c) a)

[procedure (list-tail list k)

list は最低でも k の大きさがなければならない。 list-tail 手続きは最初の k 要素を省略することで得られた list の対の部分連鎖を返す。

(list-tail ’(a b c d) 2)                         ⇒  (c d)

実装系の義務: 実装系は list が最低でも長さ k である対の連鎖であるか確認しなければならない。この長さを越えた対の連鎖については確認すべきではない。

[procedure] (list-ref list k)

list は最低でも k + 1 の長さのリストでなければならない。 list-ref 手続きは listk 番目の要素を返す。

(list-ref ’(a b c d) 2)                         ⇒ c

実装系の義務: 実装系は list が最低でも長さ k + 1 の対の連鎖であることを確認しなければならない。この長さを越えて対のリストであることを確認すべきではない。

[procedure] (map proc list1 list2)

list はすべて同じ長さでなければならない。 proclist と同じ個数の引き数を取り、ひとつの値を返さなければならない。 proclist のいずれも変更すべきではない。

map 手続きは proc を要素指向で list の要素に適用し、その結果を順番にリストにして返す。 proc は常に map 自体と同一の動的環境で呼び出される。 proclist の要素に適用される時の順序は規定されていない。 map から複数回返った場合にも、先に戻された値は変更されない。

(map cadr ’((a b) (d e) (g h)))   
                ⇒  (b e h)

(map (lambda (n) (expt n n))
     ’(1 2 3 4 5))                
                ⇒  (1 4 27 256 3125)

(map + ’(1 2 3) ’(4 5 6))                 ⇒  (5 7 9)

(let ((count 0))
  (map (lambda (ignored)
         (set! count (+ count 1))
         count)
       ’(a b)))                         ⇒  (1 2) or (2 1)

実装系の義務: 実装系は list がすべて同じ長さであることを確認するべきである。実装系は上で述べたように proc を適用することにより行われるかぎりの proc への制約を確認しなければならない。実装系は proc を適用する前にそれが適切な引き数であるか確認してもかまわない。

[procedure] (for-each proc list1 list2)

list はすべて同じ長さでなければならない。 proclist と同じ個数の引き数を取らなければならない。 proc はいずれの list も変更すべきではない。

for-each 手続きは要素指向に list の要素に、最初の要素から最後の要素に向かって副作用目的で proc を適用する。 proc は常に for-each 自体と同一の動的環境で呼び出される。 for-each の戻り値は規定されていない。

(let ((v (make-vector 5)))
  (for-each (lambda (i)
              (vector-set! v i (* i i)))
            ’(0 1 2 3 4))
  v)                                        ⇒  #(0 1 4 9 16)

(for-each (lambda (x) x) ’(1 2 3 4)) 
                ⇒ unspecified

(for-each even? ’())         ⇒ unspecified

実装系の義務: 実装系は list がすべて同じ長さであることを確認するべきである。実装系は上で述べたように proc を適用することにより行われるかぎりの proc への制約を確認しなければならない。実装系は proc を適用する前にそれが適切な引き数であるか確認してもかまわない。

: for-each の実装は最後の要素に対して proc を末尾呼び出しをしてもしなくてもかまわない。


Last modified : 2012/02/07 07:45:46 UTC