For Development HEAD DRAFTSearch (procedure/syntax/module):

Next: , Previous: , Up: 基本的な構文   [Contents][Index]

4.4 代入

Special Form: set! symbol expression
Special Form: set! (proc arg …) expression

[R7RS+ base][SRFI-17] まずexpressionが評価されます。最初の形式では、symbolへの束縛が expressionの結果を指すように変更されます。 もしsymbolがローカルに束縛されていない場合は、グローバルな変数symbolが 存在していなければなりません。そうでなければエラーが報告されます。

2番目の形式はSRFI-17に定義されている「一般化されたset!」です。 これは構文的な装飾であり、実際は以下のように解釈されます。

((setter proc) argexpression)

CommonLispのsetfとは、setter手続きに渡される引数の順序が異なることに注意して下さい。

例:

(define x 3)
(set! x (list 1 2))
x                    ⇒ (1 2)

(set! (car x) 5)
x                    ⇒ (5 2)
Macro: set!-values (var …) expr
Macro: set!-values (var … . varn) expr
Macro: set!-values var expr

[SRFI-210] 複数の変数を同時に更新します。Exprは与えられた変数と同じ 数だけの値を生成しなけばなりません。各値が対応するvarに セットされます。

(define a 0)
(define b 1)
(define c 2)
(set!-values (a b) (values 3 4))
a ⇒ 3
b ⇒ 4
(set!-values (a b) (values b a))
a ⇒ 4
b ⇒ 3
(set!-values (a b . c) (values 1 2 3 4))
a ⇒ 1
b ⇒ 2
c ⇒ (3 4)

define-valuesも参照 (定義)。

Function: setter proc

[SRFI-17] 手続きprocのsetter手続きを返します。 procがsetter手続きを持たない場合の動作は未定義です。

ある関数fのsetter手続きgとは、もし(g a b … v)のように 呼ばれた場合、次の(f a b …)vを返すようになる手続きのことです。

ある手続きにsetter手続きを関連付けるには、setter自身のsetter手続きを使うことが できます。

(set! (setter f) g)

特定の手続きにsetter手続きを「ロック」することができます。システム既定のsetter手続き、 例えばcarに対するset-car!等はロックされていて、上記のような方法で 変更することは出来ません。ユーザ定義手続きにsetter手続きをロックするには下記の getter-with-setterを使います。

procが手続きでない場合は、object-applyジェネリックファンクションの setterが返されます。これにより、適用可能オブジェクトが一般化されたset! でもうまく動作します。詳しくは適用可能なオブジェクトを参照して下さい。

Function: has-setter? proc

procがsetter手続きを持っている場合は#tを返します。

Function: getter-with-setter get set

[SRFI-17] 2つの手続き、getsetを取り、新しい手続きを返します。 新しい手続きはgetと同じ動作をし、そのsetter手続きはsetにロックされて います。

この手続きは、SRFI-17によれば、setter手続きのインライン展開を可能にするための ものですが、Gaucheではまだそのような最適化は実装されていません。

Gaucheでは、一般化されたset!と同じセマンティクスを持ついくつかのマクロが定義 されています。これらはset!を使った形に展開されます。

Macro: push! place item

itemplaceの値をコンスし、その結果を再びplaceにセットします。 placeset!と同様に、 変数か(proc arg …)という形式でなければなりません。 このマクロの戻り値は未定義です。

(define x (list 2))
(push! x 3)
x ⇒ (3 2)

(push! (cdr x) 4)
x ⇒ (3 4 2)

placeがリストの場合、だいたいこんなふうに展開されます。

(push! (foo x y) item)
 ≡
 (let ((tfoo foo)
       (tx x)
       (ty y))
   ((setter tfoo) tx ty (cons item (tfoo tx ty))))

註:Common Lispのpushマクロは引数を逆の順番で取ります。 push!は他の副作用を持つ形式との互換性を考えてこの順番としました。 Perlのpush関数はpush!マクロと同じ引数順ですが、 itemはシーケンスの末尾に追加されます (Perlのunshiftの方が push!の動作に近いです)。 Perlのpushオペレータの動作が必要ならQueueが使えます (data.queue - キュー参照)。

Macro: push-unique! place item [equal]

placeの値はリストでなければなりません。itemがそのリスト中に なければ、placeitemを先頭にコンスした値に更新されます。 itemが既にplaceの値の中にあれば、何も起きません。

itemが既にある値と等しいかどうかはequal手続きで比較されます。 省略された場合はeqv?が使われます。

Common Lispのpushnewに似ていますが、引数の順序が異なります。

data.queueenqueue-unique!queue-push-unique!も 参照してください(data.queue - キュー)。

(define v (vector '("a")))

(push-unique! (vector-ref v 0) "b")
v ⇒ #(("b" "a"))

(push-unique! (vector-ref v 0) "A" string-ci=?)
v ⇒ #(("b" "a"))

(push-unique! (vector-ref v 0) "A")
v ⇒ #(("A" "b" "a"))
Macro: pop! place

placeの値を取り出し、そのcdrplaceにセットします。 元の値のcarを返します。

(define x (list 1 2 3))
(pop! x) ⇒ 1
x ⇒ (2 3)

(define x (vector (list 1 2 3)))
x ⇒ #((1 2 3))
(pop! (vector-ref x 0)) ⇒ 1
x ⇒ #((2 3))

註:この動作はCommon Lispのpopと同じです。 Perlのpopはシーケンスの末尾から値を取ります。 Perlならshiftpop!の動作に近いです。

Macro: inc! place :optional delta
Macro: dec! place :optional delta

placeの値を評価します。それは数値にならなければなりません。 その値にdeltaが加算(inc!)もしくは減算(dec!)され、 結果がplaceに格納されます。deltaの既定値は1です。

Common Lispのincfdecfに似ていますが、 戻り値を使うことは出来ません。

Macro: update! place proc

push!等のマクロの一般化された形式です。 procは一つの引数を取り、一つの値を返す手続きでなければなりません。 placeの値がprocに渡され、procの結果がplaceに格納されます。

(define a (cons 2 3))
(update! (car a) (lambda (v) (* v 3)))
a ⇒ (6 . 3)

(update! (cdr a) (cut - <> 3))
a ⇒ (6 . 0)
Macro: rotate! place0 place1 … placeN

次のコードと概ね同じです:

(let ((tmp0 place0) (tmp1 place1) ... (tmpN placeN))
  (set! place0 tmp1)
  (set! place1 tmp2)
    :
  (set! placeN tmp0))

但し、place(proc arg ...)の形であった場合、 各argは1度しか評価されません。

二ヶ所の値を交換するのにも使えます:

(let ((x (vector 1 2)))
  (rotate! (~ x 0) (~ x 1))
  x)  ⇒ #(2 1)

これはCommon Lispのrotatefに似ています。


Next: , Previous: , Up: 基本的な構文   [Contents][Index]


For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT