コラム: リストリテラルは破壊的に変更してはいけない
Schemeでリストリテラルを破壊的に変更するのはエラー(誤り)です。
破壊的に変更することが可能なのはconsやlistで構築されたリストだけです。
例えばリストリテラルに束縛されたlstを定義したとします。
gosh> (define lst '(1 2 3))
lst
gosh> lst
(1 2 3)
set-car!でlstの要素を破壊的に変更してみます。
gosh> (set-car! lst 100)
#<undef>
gosh> lst
(100 2 3)
このコードは現状のGaucheバージョン0.8.10で動作してしまいますが、
Schemeの仕様上はエラーです。
コラム: エラーのときのScheme処理系の振舞い
Schemeの現在の仕様であるR5RSでは、
リスト要素が破壊的に変更されたときをはじめ、
エラーのとき何が起こるべきかについて規定していません。
このためエラーでの動作は処理系ごとに異なります。
Schemeの次期仕様であるR6RSではエラー時に何が起きるべきか、
もっと厳密に定められる予定です。
もしリストリテラルを変更する必要があるなら、
list-copy手続きでコピーを作成し、コピーの方を破壊的に変更してください。
gosh> (define lst '(1 2 3))
lst
gosh> lst
(1 2 3)
gosh> (define lst-cp (list-copy lst))
lst-cp
gosh> lst-cp
(1 2 3)
gosh> (set-car! lst-cp 100)
#<undef>
gosh> lst
(1 2 3)
gosh> lst-cp
(100 2 3)
リテラル値、つまり定数値を破壊的に変更してはならない原則は、
例えば文字列リテラルについても同様です。
gosh> (string-set! "abc" 0 #\x)
*** ERROR: attempted to modify an immutable string: "abc"
Stack Trace:
_______________________________________