Gaucheプログラミング(立読み版) > 文法 > 構文 > 束縛(bind) > 破壊的変更と副作用 > リスト要素の破壊的変更


[Prev] [Next] [Up] [Contents][フレーム表示] [フレーム解除

リスト要素の破壊的変更 応援する 

空リスト以外のリストは対(pair)で構成されています。 対の要素の値はcarとcdrで参照することができます。

  gosh> (define lst (cons "abc" (cons 3 '())))
  lst
  gosh> lst
  ("abc" 3)
  gosh> (car lst)
  "abc"
  gosh> (cdr lst)
  (3)

carとcdrで参照できる要素の値を破壊的に変更する手続きがset-car!set-cdr!です。

  gosh> (set-car! lst #\r)
  #<undef>
  gosh> lst
  (#\r 3)

まず対のcar要素を文字#\rに置き換えました。

  gosh> (set-cdr! lst '(a b c))
  #<undef>
  gosh> lst
  (#\r a b c)

つぎに対のcdr要素をリスト(a b c)に置き換えました。

面白い使い方としては対の要素に自分自身を代入することもできます。

  gosh> (define lst (list 2 "hello" 3 a #\b))
  lst
  gosh> lst
  (2 "hello" 3 a #\b)

  gosh> (set-car! lst lst)
  #<undef>
  gosh> lst
  #0=(#0# "hello" 3 a #\b)

ここではリスト(2 "hello" 3 a #\b)のcarにこのリスト自身を代入しました。

carを取り出してみると

  gosh> (car lst)
  #0=(#0# "hello" 3 a #\b)
  gosh> (car (car lst))
  #0=(#0# "hello" 3 a #\b)

同じ値が返されます。ここで、

  #数=値

は値に#数という名前をつけ、

  #数#

で、#数の名前が指している値を参照するということになっています。この機能を使うと循環したリストを作成できます。


コラム: リストリテラルは破壊的に変更してはいけない

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:
 _______________________________________

[Prev] [Next] [Up] [Contents][フレーム表示] [フレーム解除

このサイトについて|ヘルプ|Q&A|個人情報保護|プライバシーポリシー|利用規約|コメント・トラックバック規約|削除規程|広告掲載
Copyright (c) 2005-2007 Time Intermedia Corporation