For Gauche 0.9.5


Next: , Previous: , Up: 組み込みライブラリ   [Contents][Index]

6.6 ペアとリスト

ペアとリストはSchemeにおける最も基本的なデータ構造のひとつです。 Gaucheのコアは全ての標準のリスト手続きと、多くのScheme実装に見られる 便利な手続きのいくつかを提供します。それらで足りない場合は さらに多くの手続きがリストライブラリ組み合わせ といったモジュールで提供されています。 また、リストに限らないジェネリックなシーケンス/コレクションの操作が コレクションフレームワークシーケンスフレームワークで提供されています。


Next: , Previous: , Up: ペアとリスト   [Contents][Index]

6.6.1 pairクラスとnullクラス

Builtin Class: <list>

リストを表す抽象クラスで、クラス<null>とクラス<pair>の親クラスです。 クラス<sequence>を継承します。

循環リストやドットリストも<list>クラスのインスタンスですが、 list?は偽の値を返すことに注意して下さい。

(use srfi-1)
(list? (circular-list 1 2)) ⇒ #f
(is-a? (circular-list 1 2) <list>) ⇒ #t
Builtin Class: <null>

空リストのクラスです。()がこのクラスの唯一のインスタンスです。

Builtin Class: <pair>

ペアのクラスです。


Next: , Previous: , Up: ペアとリスト   [Contents][Index]

6.6.2 リストに関する述語

Function: pair? obj

[R7RS] objがペアなら#tを、そうでなければ#fを返します。

Function: null? obj

[R7RS] objが空リストなら#tを、そうでなければ#fを返します。

Function: null-list? obj

[SRFI-1] obj が空リストなら#tを、ペアなら#fを返し、 それ以外のときはエラーを報告します。

リスト終了条件を検査する時に、正しいリスト以外を除外したい場合に null?の代わりに使えます。

Function: list? obj

[R7RS] objが正しいリストなら#tを、そうでなければ#fを返します。 この手続きはobjがドットリストや循環リストなら#fを返します。

下に説明する、 proper-list?circular-list?dotted-list? といった手続きも参照してください。

Function: proper-list? x

[SRFI-1] x が真性リストであれば #t を返します。

Function: circular-list? x

[SRFI-1] x が循環リストであれば #t を返します。

Function: dotted-list? x

[SRFI-1] x が有限の大きさで、空リストで終端していないリストなら #t を返します。これには、ペアではなく、空リストもない値(たとえば シンボルや数値)のような長さ0のドットリストと考えられるものを含みます。


Next: , Previous: , Up: ペアとリスト   [Contents][Index]

6.6.3 リストの作成

Function: cons obj1 obj2

[R7RS] obj1obj2のペアを作成します。

(cons 'a 'b) ⇒ (a . b)
Function: make-list len :optional fill

[R7RS][SRFI-1] 長さlenの正規のリストを返します。引数fillが与えられていれば、各要素は fillになります。そうでなければ各要素の値は不定です。

(make-list 5 #t) ⇒ (#t #t #t #t #t)
Function: list obj …

[R7RS] 要素がobj …であるリストを作成します。

(list 1 2 3) ⇒ (1 2 3)
(list) ⇒ ()
Function: list* obj1 obj2 …
Function: cons* obj1 obj2 …

[SRFI-1] listとほぼ同じですが、最後の引数が作成されるリストの最後のペアのcdrになります。 二つの手続きは全く同じです。Gaucheはもともとlist*を持っていましたが、 SRFI-1がcons*という名前を定義しました。

(list* 1 2 3) ⇒ (1 2 . 3)
(list* 1) ⇒ 1
Function: list-copy list

[R7RS][SRFI-1] listの浅いコピーを行います。 listが循環リストの場合、この手続きは停止しません。

Function: iota count :optional (start 0) (step 1)

[SRFI-1] startから始まり、stepずつ増加する、 count 個の要素からなる数値のリストを返します。countは 非負の整数でなければなりません。startstepが ともに正確数であれば、結果は正確数のリストになります。そうでなければ 結果は非正確数のリストです。

(iota 5)        ⇒ (0 1 2 3 4)
(iota 5 1 3/7)  ⇒ (1 10/7 13/7 16/7 19/7)
(iota 5 0 -0.1) ⇒ (0 -0.1 -0.2 -0.3 -0.4)

この手続きはリストを最後まで作って返します。リストが短ければ 十分速いですが、何万という数をリストにしたければ、遅延リストを使った方が 良いかもしれません。liotaを見てください(遅延シーケンス参照)。

Macro: cond-list clause …

条件によりエントリを追加することによりリストを構築します。 それぞれのclauseは条件と式を持ちます。 条件が真であれば、関連する式の結果が結果のリストの構築に使われます。 条件が偽であれば、何も挿入されません。

clauseは、以下のフォームのうちの1つでなければなりません。

(test expr …)

testが評価され、それが真ならばexpr …が評価され、 戻り値が結果の一部となります。exprが与えられなければ、 testの結果が偽でなければその結果が使われます。

(test => proc)

testが評価され、それが真ならばprocがその値とともに 呼ばれ、その戻り値が結果を構築するために使われます。

(test @ expr …)

(test expr …)のように動作しますが、最後のexprの 値はリストでなければならず、それは結果のリストに(unquote-splicingのように) スプライスされます。

(test => @ proc)

(test => proc)のように動作しますが、procの戻り値 はリストでなければならず、それは結果のリストに(unquote-splicingのように) スプライスされます。

(let ((alist '((x 3) (y -1) (z 6))))
 (cond-list ((assoc 'x alist) 'have-x)
            ((assoc 'w alist) 'have-w)
            ((assoc 'z alist) => cadr)))
  ⇒ (have-x 6)

(let ((x 2) (y #f) (z 5))
  (cond-list (x @ `(:x ,x))
             (y @ `(:y ,y))
             (z @ `(:z ,z))))
  ⇒ (:x 2 :z 5)

Next: , Previous: , Up: ペアとリスト   [Contents][Index]

6.6.4 リストへのアクセスと変更

Function: car pair
Function: cdr pair

[R7RS] それぞれpairのcarとcdrを返します。

Function: set-car! pair obj
Function: set-cdr! pair obj

[R7RS] pairのcarもしくはcdrをobjで置き換えます。

注: (setter car)set-car! であり、 (setter cdr)set-cdr! です。

Function: caar pair
Function: cadr pair

Function: cdddar pair
Function: cddddr pair

[R7RS] caar(car (car x)), cadr(car (cdr x)), 等々。

R7RSでは、2レベルよりも深いアクセサは(scheme cxr)ライブラリに含まれます。

対応するsetterも定義されています。

(let ((x (list 1 2 3 4 5)))
  (set! (caddr x) -1)
  x)
  ⇒ (1 2 -1 4 5)
Function: length list

[R7RS] 正規のリストlistの長さを返します。 listがドットリストならばエラーが起きます。 listが循環リストの場合、この関数は無限ループします。

Function: length+ x

[SRFI-1] x が真性リストなら、その長さを返します。 x がそうでなければ(たとえ循環リストであっても) #f を返します。

Function: length=? x k
Function: length<? x k
Function: length<=? x k
Function: length>? x k
Function: length>=? x k

それぞれ、リストxの長さがkと等しいか、k未満か、k以下か、kより大きいか、 k以上かの場合に#tを、そうでなければ#fを返します。 この関数はk要素までしかリストを辿らないので、特にxが遅延シーケンス (遅延シーケンス参照)である場合に、必要以上にリストを実体化しなくて済みます。

xはドットリストや循環リストでも構いません。 ドットリストの長さを数える際には最後のペアのcdrは無視します。 つまり、ペアでないオブジェクトの長さは0で、(a . b)の長さは1になります。 循環リストは無限の長さを持つとみなします。

(length<=? '(a b) 2)  ⇒ #t
(length<=? '(a b) 1)  ⇒ #f
(length<=? '()    0)  ⇒ #t

;; dotted list cases
(length<=? 'a       0)  ⇒ #t
(length<=? '(a . b) 0)  ⇒ #f
(length<=? '(a . b) 1)  ⇒ #t

註: これらの手続きの名前は混乱を招きやすいかもしれません。something<=?等の 名前は通常、同じ型のオブジェクト同士の比較に使われるからです。 残念ながら、今のところより良い名前を思いつけていません。

Function: take x i
Function: drop x i

[SRFI-1] take はリスト x の最初のi個の要素を返します。 drop はリスト x の最初のi個の要素を除いたリストを返します。

(take '(a b c d e) 2) => (a b)
(drop '(a b c d e) 2) => (c d e)

x はあらゆる値をとりえます。

(take '(1 2 3 . d) 2) => (1 2)
(drop '(1 2 3 . d) 2) => (3 . d)
(drop '(1 2 3 . d) 3) => d

dropxi 回 cdr 操作をおこなうのと全く 同じです。返される値は、x と共通の末尾を共有します。一方、 take は、引数のリストが長さ0でないリストなら必ず新しいリストの 領域を確保します。

i がリスト x の終端を超えたらエラーが発生します。 より寛容な手続きについては、下のtake*drop*を見てください。

あらゆる並びからの部分並びを抽出する汎用的な方法に関しては、 シーケンスのスライス にある subseq を参照してください。

Function: take* list k :optional (fill? #f) (padding #f)
Function: drop* list k

takedropのより寛容なバージョンです。 これらの手続きは、リストがkより短くてもエラーを通知しません。

その場合、take*はデフォルトではlistのコピーを 返します。もしfill?が真であれば、足りない要素の部分に paddingを追加してk要素にしたリストを返します。

一方、drop*はリストの長さが不足する場合は単に空リストを返します。

(take* '(a b c d) 3)       ⇒ (a b c)
(take* '(a b c d) 6)       ⇒ (a b c d)
(take* '(a b c d) 6 #t)    ⇒ (a b c d #f #f)
(take* '(a b c d) 6 #t 'z) ⇒ (a b c d z z)
(drop* '(a b c d) 3)       ⇒ (d)
(drop* '(a b c d) 5)       ⇒ ()

注意: 一般的な、いかなるシーケンスからのサブシーケンスの抽出については、 シーケンスのスライスsubseqを見て下さい。

Function: take-right lis k
Function: drop-right lis k

[SRFI-1] take-rightlis の最後の k個の要素 からなるリストを返します。 drop-rightlis の最後の k個の要素を 除いたリスト返します。

(take-right '(a b c d e) 2) => (d e)
(drop-right '(a b c d e) 2) => (a b c)

lis は有限リストであればOKです。

(take-right '(1 2 3 . d) 2) => (2 3 . d)
(drop-right '(1 2 3 . d) 2) => (1)
(take-right '(1 2 3 . d) 0) => d
(drop-right '(1 2 3 . d) 0) => (1 2 3)

take-right の返す値はいつでも lis の共通の末尾を共有します。 drop-right は、引数が長さが0でないリストなら、必ず新しいリストの 領域を確保します。

k がリスト lis の長さより大きければエラーが発生します。 より寛容なバージョンについては下のtake-right*, drop-right*を 参照してください。

Function: take-right* list k :optional (fill? #f) (padding #f)
Function: drop-right* list k

take*及びdrop*と同じですが、listの右端からカウントします。 これらはlistk要素より短い場合にもエラーを通知しません。 drop-right*はその場合は単に空リストを返します。 take-right*はその場合はデフォルトでlistそのものを 返しますが、fill?が真であればlistの右側に 足りない分だけpaddingを足したものを返します。その場合でも 結果の尾部はlistと共有されます。

Function: take! lis k
Function: drop-right! lis k

[SRFI-1] [SRFI-1] take および drop-right の その場で更新されるバージョンです。これらの 手続きは lis を破壊的に変更するかもしれません。

lis が循環リストなら、take! は期待されるものより短いリストを返す 可能性があります。

Function: list-tail list k :optional fallback

[R7RS] listk番目のcdrを返します。listは 正規のリストでもドットリストでも循環リストでも構いません。 (listがドットリストの場合、最後のcdrは無視されます)。

kの値が負であったりlistの長さ以上の場合、 fallback引数が与えられていればそれが返され、 そうでなければエラーが報告されます。

Function: list-ref list k :optional fallback

[R7RS+] listk番目の要素を返します。listは 正規のリストでもドットリストでも循環リストでも構いません。

もしkがリストの長さを超えていたり、負数であった場合は通常はエラーが起こります。 しかし、オプショナルな引数fallbackが与えられていた場合は、エラーは起きず fallbackが返されます。これはGaucheの拡張です。

Function: list-set! list k v

[R7RS] リストlistk番目の要素をvへと変更します。 kが0から(- リストの長さ 1)の範囲の正確な整数でない場合は エラーが報告されます。listが変更不可なリストであった場合、 エラーは報告されませんが、その後の振る舞いは不定となります。

Function: last-pair list

[SRFI-1] listの最後のペアを返します。listは 正規のリストかドットリストです。

(last-pair '(1 2 3))   ⇒ (3)
(last-pair '(1 2 . 3)) ⇒ (2 . 3)
(last-pair 1)          ⇒ error
Function: last pair

[SRFI-1] 空ではない有限リスト pair の最後の要素を返します。 これは、(car (last-pair pair)) と同等です。

(last '(1 2 3))        ⇒ 3
(last-pair '(1 2 . 3)) ⇒ 2
Function: split-at x i
Function: split-at! x i

[SRFI-1] split-at はリスト x をインデックス i の 位置で分割し、最初の i 個の要素からなるリストと、残りの末尾とを 返します。

(split-at '(a b c d e) 2) ⇒ (a b) (c d e)

split-at! はその場で更新されるバージョンです。 これは x を破壊的に更新するかもしれません。

Function: split-at* list k :optional (fill? #f) (padding #f)

SRFI-1のsplit-atの寛容なバージョンです。 take*drop*の結果を返します。

(split-at* '(a b c d) 6 #t 'z)
  ⇒ (a b c d z z) and ()
Function: slices list k :optional fill? padding

listを、それぞれの長さがkであるようなサブリスト(スライス)に 分割します。 listの長さがkの整数倍でない場合は、最後のスライスは take*と同じ方法で扱われます。つまり、デフォルトではkより 短いもの、あるいはfill?が真ならばpaddingが追加されます。

(slices '(a b c d e f g) 3)
  ⇒ ((a b c) (d e f) (g))
(slices '(a b c d e f g) 3 #t 'z)
  ⇒ ((a b c) (d e f) (g z z))
Function: intersperse item list

listの要素の間にitemを挿入します。 (引数の順番は、Haskellのintersperseと同じです。)

(intersperse '+ '(1 2 3))  ⇒ (1 + 2 + 3)
(intersperse '+ '(1))      ⇒ (1)
(intersperse '+ '())       ⇒ ()

Next: , Previous: , Up: ペアとリスト   [Contents][Index]

6.6.5 リストをたどる手続き

Function: map proc list1 list2 …

[R7RS+] 与えられたリストの各要素に対してprocを適用し、その結果をリストにして 返します。R7RSではprocの適用順序が定められていませんが、Gaucheでは 常にprocはリスト内の順番で呼ばれます。 複数のリストが与えられた場合、最も短いリストが終了した時点でprocの適用を 打ち切ります。

(map car '((a b) (c d) (e f))) ⇒ (a c e)

(map cons '(a b c) '(d e f))
  ⇒ ((a . d) (b . e) (c . f))

gauche.collectionモジュール(コレクションフレームワーク参照) を使うと、mapがリスト以外のコレクション型に対しても動作するようになります。

Function: append-map f clist1 clist2 …
Function: append-map! f clist1 clist2 …

[SRFI-1] 機能的には以下と同等ですが、若干効率が良いです:

  (apply append (map f clist1 clist2 …))
  (apply append! (map f clist1 clist2 …))

引数のリストのうち少くともひとつは有限でなければなりません。

Function: map* proc tail-proc list1 list2 …

mapとほぼ同じですが、引数の最後のペアのcdrtail-procが 適用され、その返り値が結果のリストの最後のペアのcdrになります。 この手続きは正規でないリストを引数に取ることができます。 引数のリストがひとつだけの場合、tail-procの引数は必ずペアでないオブジェクトです。

(map* - / '(1 2 3 . 4)) ⇒ (-1 -2 -3 . 1/4)

(define (proper lis)
  (map* values
        (lambda (p) (if (null? p) '() (list p)))
        lis))

(proper '(1 2 3))     ⇒ (1 2 3)
(proper '(1 2 3 . 4)) ⇒ (1 2 3 4)

二つ以上のリストが与えられた場合は、最も短いリストがtail-procの呼び出しを 決めます。map*が最も短いリストの最後のペアに達した時点で、 その時のそれぞれのペアのcdrがtail-procへと渡されます。

(map* + vector '(1 2 3 4) '(1 2 . 3))
  ⇒ (2 4 . #((3 4) 3))

註: map*という名前は、正規でないリストを作り得るlist*/cons*からの 連想でつけられました (リストの作成SRFI-1 リスト操作関数参照)。

Function: for-each proc list1 list2 …

[R7RS] 手続きprocをリストの各エレメントに対して順に適用します。 procの結果は捨てられます。for-eachの戻り値は定義されていません。 複数のリストが与えられた場合、一番短いリストが終了した時点でfor-eachは終了します。

gauche.collectionモジュール(コレクションフレームワーク参照) を使うと、for-eachがリスト以外のコレクション型に対しても動作するようになります。

Function: fold kons knil clist1 clist2 …

[SRFI-1] 基本的なリスト反復演算子です。単一のリスト clist1 = (e1 e2en) を与えられたときには、以下を返します。

(kons en … (kons e2 (kons e1 knil)) … )

n 本のリストが与えられた場合には、kons 関数は n+1 個の引数 をとる関数でなければなりません。それぞれのリストから要素をひとつずつと、 初期値 knil である「種」あるいは畳み込み状態とよばれるものです。 この畳み込み演算は、もっとも短いリストの要素がなくなったところで終了します。 与えられるリストの少くともひとつは有限でなければなりません。

例:

(fold + 0 '(3 1 4 1 5 9)) ⇒ 23 ;sum up the elements
(fold cons '() '(a b c d e)) ⇒ (e d c b a) ;reverse
(fold cons* '() '(a b c) '(1 2 3 4 5))
    ⇒ (c 3 b 2 a 1) ;n-ary case
Function: fold-right kons knil clist1 clist2 …

[R6RS][SRFI-1] 基本的な再帰演算子です。単一のリスト clist1 = (e1 e2en) を与えられたときには、以下を返します。

(kons e1 (kons e2 … (kons en knil)))

n 本のリストが与えられた場合には、kons 関数は n+1 個の引数 をとる関数でなければなりません。それぞれのリストから要素をひとつずつと、 初期値 knil である「種」あるいは畳み込み状態とよばれものです。 この畳み込み演算は、もっとも短いリストの要素がなくなったところで終了します。 与えられるリストの少くともひとつは有限でなければなりません。

例:

(fold-right cons '() '(a b c d e))
   ⇒ (a b c d e) ;copy list
(fold-right cons* '() '(a b c) '(1 2 3 4 5))
   ⇒ (a 1 b 2 c 3) ;n-ary case
Function: fold-left snok knil clist1 clist2 …

[R6RS] これは左結合のfoldの別バージョンです。一つのリスト clist1 = (e1 e2en) が与えられた場合、次の値を返します。

(snok (… (snok (snok knil e1) e2) …) en)

上のfoldと見比べてみてください。結合の順序は同じですが、 snokに渡される引数の順序が、foldにおいてkonsに渡される 引数の順序とは逆になっています。snokが可換な演算であれば、 foldfold-leftの結果は同じになります。

(fold-left + 0 '(1 2 3 4 5) ⇒ 15

(fold-left cons 'z '(a b c d))
  ⇒ ((((z . a) . b) . c) . d)

(fold-left (^[a b] (cons b a)) 'z '(a b c d))
  ⇒ (a b c d z)

二つ以上のリストが渡された場合、snokは現在のknil値および 入力リストclist1 clist2 … の対応する要素を引数として 呼び出されます。

(fold-left list 'z '(a b c) '(A B C))
  ⇒ (((z a A) b B) c C)

註:多くの関数型言語で左結合および右結合の畳み込み操作が定義されていますが、 それはfold-leftfold-rightに相当します。 (例: Haskellのfoldlfoldr。) Schemeでは、まずSRFI-1によってfoldfold-rightが 左/右結合の畳み込み演算として導入され、R6RSでfold-leftが定義されました。 (但し、R6RSのfold-leftではclist1 clist2 …の 長さがすべて同じでない場合の動作は未定義ですが、Gaucheでは 最短のリストが終了した時点でそれまでの結果が返されます。)

Function: reduce f ridentity list
Function: reduce-right f ridentity list

[SRFI-1] fold および fold-right の変形バージョンです。 f は二項演算子でなければなりません。 また、ridentityf の入力として許される あらゆる値 x について以下を満していなければなりません。

 (f x ridentity) ≡ x

これらの関数は実質的に foldfold-right と同じことを 行いますが、ridentityには上記の性質があるため、 fridentityには適用されません。 ridentityが使われるのはlistが空の場合だけです。

Function: filter pred list
Function: filter! pred list

[SRFI-1] 手続き predlist の各要素に適用され、 pred が真を返す要素のリストが返されます。

(filter odd? '(3 1 4 5 9 2 6)) ⇒ (3 1 5 9)

filter! はその場で更新されるバージョンです。結果を生成するために list を破壊的に変更するかもしれません。

Function: filter-map f clist1 clist2 …

map と似ていますが、真になる場合の値のみが保存されます。 引数として与えられるリストの少くともひとつは有限でなければなりません。

(filter-map (lambda (x) (and (number? x) (* x x)))
            '(a 1 b 3 c 7))
  ⇒ (1 9 49)
Function: remove pred list
Function: remove! pred list

[SRFI-1] 手続き predlist の各要素に適用され、 pred が偽を返す要素のリストが返されます。

(remove odd? '(3 1 4 5 9 2 6)) ⇒ (4 2 6)

remove! はその場で更新されるバージョンです。結果を生成するために list を破壊的に更新するかもしれません。

Function: find pred clist

[SRFI-1] clist の各要素に対して左から右に pred を適用し、 pred が真を返す最初の要素を返します。predを満たす要素が 無い場合は#fを返します。

Function: find-tail pred clist

[SRFI-1] clist の各要素に対して左から右に pred を適用し、pred が 真を返す場合、その car がその要素であるペアを返します。 predを満たす要素が無い場合は#fを返します。

Function: any pred clist1 clist2 …

[SRFI-1] clist の各要素に pred を適用し、predが偽でない 値を返したら直ちにその値を返します。 predが偽でない値を返す前にリストの要素を使いきってしまったら #fが返ります。

Function: every pred clist1 clist2 …

[SRFI-1] clist の各要素に pred を順に適用し、predが 偽を返した場合、直ちに偽を返します。全てのpredの適用が 偽でない値を返した場合は、最後に返された値が返されます。

Function: count pred clist1 clist2 …

[SRFI-1] n をゼロから与えられたリストのうち最も短いリストの 長さまでとして、pred 手続きを与えられたリストの n 番目の要素に それぞれ適用します。 pred が真を返した数が返ります。

(count even? '(3 1 4 1 5 9 2 5 6)) ⇒ 3
(count < '(1 2 4 8) '(2 4 6 8 10 12 14 16)) ⇒ 3

引数で与えられるリストの少くともひとつは有限でなければなりません。

(count < '(3 1 4 1) (circular-list 1 10)) ⇒ 2
Function: delete x list :optional elt=
Function: delete! x list :optional elt=

[SRFI-1] 以下と同等です。

  (remove (lambda (y) (elt= x y)) list)
  (remove! (lambda (y) (elt= x y)) list)

比較手続き elt= はデフォルトでは equal? です。

Function: delete-duplicates list :optional elt=
Function: delete-duplicates! list :optional elt=

[SRFI-1] list から重複した要素を取り除きます。list 中に等しい要素が 複数ある場合、一番左がわにある最初のものだけが残ります。これらの 生き残った要素間の順番は最初のリストの順番が保存されます。 比較手続き elt= のデフォルト値は、equal? です。


Next: , Previous: , Up: ペアとリスト   [Contents][Index]

6.6.6 他のリスト手続き

Function: append list …

[R7RS] 渡されたリストの要素を繋げたリストを返します。最後の引数の部分以外は新しいセルがアロケート されて使われます。最後の引数は正規のリストである必要がありません。その場合、結果は正規でない リストとなります。

Function: append! list …

[SRFI-1] 渡されたリストの要素を繋げたリストを返します。最後の引数以外のリストのセルは、結果を 作成するために再利用されるかもしれません。 最後の引数は正規のリストである必要はありません。

Function: concatenate list-of-lists
Function: concatenate! list-of-lists!

[SRFI-1] それぞれ、(apply append list-of-lists) および (apply append! list-of-lists) と同等ですが、 applyのオーバヘッドが無い分、わずかに効率的です。

Function: reverse list :optional (tail '())
Function: reverse! list :optional (tail '())

[R7RS+, SRFI-1+] listの要素を逆順に並べたリストを返します。 reverseは常に新たにリストをアロケートしますが、 reverse!は結果を作るためにlistのセルを再利用するかもしれません。 但し、listの先頭のセルがreverse!の結果でも先頭になるとは 限らないので、listが変更されることを当てにするのではなく、 reverse!の戻り値を利用する必要があります。

省略可能引数tailが与えられた場合、それは結果のリストの末尾に 付け足されます (tail部分はコピーされません)。 これは、既にある結果のリストに新たに作った結果を付け足すイディオムで 便利です。

(reverse '(1 2 3 4 5)) ⇒ (5 4 3 2 1)
(reverse '(1 2 3) '(a b)) ⇒ (3 2 1 a b)

tail引数はGauche独自の拡張で、 伝統的なSchemeのreverseにはありませんが、 次の対応を考えると、そう不自然なことではありません。

(reverse xs)      ≡ (fold cons xs '())
(reverse xs tail) ≡ (fold cons xs tail)
Function: append-reverse rev-head tail
Function: append-reverse! rev-head tail

[SRFI-1] [SRFI-1] 2引数のreverseおよびreverse!と同等です。 srfi-1との互換のために用意されています。

Function: memq obj list
Function: memv obj list
Function: member obj list :optional obj=

[R7RS][SRFI-1] listからobjを探します。もしlistn番目の要素が objと同一ならば、(list-tail list n)を返します。 memqは同一性の判定にeq?を、memveqv?を、 memberequal?を使います。 objlist中に見つからなければ#fが返されます。

memberに省略可能引数obj=が与えられた場合は、 その手続きがequal?のかわりにobjと要素を比較するのに使われます。

(memq 'a '(a b c))          ⇒ (a b c)
(memq 'b '(a b c))          ⇒  (b c)
(memq 'a '(b c d))          ⇒ #f
(memq (list 'a) '(b (a) c)) ⇒ #f
(memv 101 '(100 101 102))   ⇒ (101 102)

Previous: , Up: ペアとリスト   [Contents][Index]

6.6.7 連想リスト

Function: acons obj1 obj2 obj3

(cons (cons obj1 obj2) obj3) を返します。 連想リストの先頭に新しいエントリを加えるのに便利です。

(この手続きはSRFI-1ではalist-consという名前で定義されています。 リストライブラリ参照)。

(acons 'a 'b '((c . d))) ⇒ ((a . b) (c . d))
Function: alist-copy alist

[SRFI-1] alist の新しい複製を返します。alist の背骨の部分、 およびキーと値を指す各セルは複製されます。

(define a (list (cons 'a 'b) (cons 'c 'd)))
a ⇒ ((a . b) (c . d))

(define b (alist-copy a))
b ⇒ ((a . b) (c . d))

(set-cdr! (car a) 'z)
a ⇒ ((a . z) (c . d))
b ⇒ ((a . b) (c . d))
Function: assq obj list
Function: assv obj list
Function: assoc obj list :optional key=

[R7RS][SRFI-1] listの各要素はペアでなければなりません。 これらの手続きは、listの要素であるペアのうち、そのcarが objと一致するペアを左から探して行きます。もし見付かればそのペアが、 見付からなければ#fが返されます。 assqは比較関数にeq?を、assveqv?を、 assocequal?をそれぞれ用います。

assocの省略可能引数が与えられた場合は、 その手続きがequal?のかわりに、 objと各キーとの同一性判定に使われます。

Function: alist-delete key alist :optional key=
Function: alist-delete! key alist :optional key=

[SRFI-1] alist から keyと同じキーをもつすべてのセルを削除します。 比較は key= で行います。これのデフォルト値は eqv? です。

その場で更新を行うバージョン alist-delete! は元の alist を変更してしまうことがあります。

Function: rassoc key alist :optional eq-fn
Function: rassq key alist
Function: rassv key alist

与えられるkeyalistのそれぞれの要素で、carの代わりに cdrにマッチするような逆になった連想リストです。 両方向の連想リストと理解すると簡単です。 rassocは、そのデフォルトがequal?である、オプションの 比較関数を取ります。rassqeq?rassveqv?を 使います。

Function: assoc-ref alist key :optional default eq-fn
Function: assq-ref alist key :optional default
Function: assv-ref alist key :optional default

これらの手続きは、他の*-ref手続きと対称的な連想リストへの アクセスを提供します。(assoc, assq, assvと 引数の順序が逆であることに注意しえください。*-ref手続きは、 コンテナを最初に、要素を次に取ります)。

これは、一般的な連想リストアクセスのパターンを提供します。

(assoc-ref alist key default eq-fn)
 ≡
  (cond [(assoc key alist eq-fn) => cdr]
        [else default])))

defaultが省略されると、#fが使われます。

assoc-refは、そのデフォルトがequal?である、オプションの 比較関数eq-fnを取ります。assq-refeq?を、 assv-refeqv?をそれぞれ使います。

Function: rassoc-ref alist key :optional default eq-fn
Function: rassq-ref alist key :optional default
Function: rassv-ref alist key :optional default

assoc-refの逆連想リストバージョンです。

(rassoc-ref alist key default eq-fn)
 ≡
  (cond ((rassoc key alist eq-fn) => car)
        (else default))))

オプショナル引数の意味は、assoc-refと同じです。

Function: assoc-set! alist key val :optional eq-fn
Function: assq-set! alist key val
Function: assv-set! alist key val

alist(key . val)のペアが追加された連想リストを返します。 alistがすでにkeyをキーとする要素を持っている場合、 その要素のcdrは破壊的にvalに変更されます。 alistkeyをキーとする要素を持っていない場合は、 新しいペアが作成され、alistの一番前に追加されます。 したがって、key-valペアが追加されたことを保証するために その戻り値を使うべきです。

assoc-set!は、そのデフォルトがequal?である、オプションの 比較関数eq-fnを取ります。assq-set!eq?を、 assv-set!eqv?を、それぞれ使います。


Previous: , Up: ペアとリスト   [Contents][Index]