一般化されたset!

CommonLispのsetfと同じようなことは、set!で出来ると教えてもらった。
これをobject-applyと組み合わせれば、Arcの=と同じようなことも出来る。

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

Function: setter proc
[SRFI-17] 手続きprocのsetter手続きを返します。 procがsetter手続きを持たない場合の動作は未定義です。
ある関数fのsetter手続きgとは、もし(g a b … v)のように呼ばれた場合、次の(f a b …)がvを返すようになる手続きのことです。

http://practical-scheme.net/gauche/man/gauche-refj_25.html

準備

以下の3行を読み込ませる

(use gauche.sequence)
(define-method object-apply (obj key) (ref obj key))
(define-method (setter object-apply) (obj key val) (set! (ref obj key) val))

リストの場合

gosh> (define ls '(a b c))
gosh> ls
(a b c)
gosh> (ls 2)
c
gosh> (set! (ls 2) 'x)
gosh> ls
(a b x)

文字列の場合

gosh> (define st (string #\a #\b #\c))
gosh> st
"abc"
gosh> (st 2)
#\c
gosh> (set! (st 2) #\x)
gosh> st
"abx"

ハッシュの場合

gosh> (define ht (hash-table 'eq? '(a . 1) '(b . 2)))
gosh> ht
#<hash-table eq? 0x8233c80>
gosh> (use util.list)
gosh> (hash-table->alist ht)
((b . 2) (a . 1))
gosh> (ht 'b)
2
gosh> (set! (ht 'b) 3)
gosh> (hash-table->alist ht)
((b . 3) (a . 1))

おぼえがき

(define st "abc")としなかったのは、リテラル文字列は変更不可能だから。
リストでも文字列でもハッシュでも同じように出来る、というために文字列の例も出したが、文字列でこのやり方をするのは非推奨らしい。

なお、ダブルクォートで囲って作成した文字列は変更不可能です。その他の方法で作成した文字列はstring-set!で変更可能です。

2007/04/29 16:18:47 shiro
「ダブルクォートで囲って作成した文字列は変更不可能」なのはそれがリテラルだから。
リテラル文字列は変更不可能」と言っておけばよい。
string-set!は *強く非推奨* です。書かなくても良いくらいだけど、いちおうR5RSに
入ってるから触れたいというのなら、「なお、リテラル以外の文字列はstring-set!で
変更できますが、そのようなスタイルはGaucheでは推奨されません。」の1行くらいに
とどめといてください。

2007/04/29 16:21:00 shiro
もう少し言うと、Gaucheでのstring-set!は、「その一文字分だけを置き換えた文字列を
新たに作成する」というふうに実装されています。したがってstring-set!を使って
性能的に特をすることはまったくありません。素直に文字列の断片を自分で集めて
最後にstring-appendするなりすべきです。

http://karetta.jp/article/book/007376/007378/commentList#commentList