私はもう少しelispを教えています、そして次の問題に遭遇しました:
リスト変数をリセットしたい場合、最初の評価後に更新されません。ここにいくつかのサンプルコードがあります:
(defun initilize ()
(setq example '(3)))
(defun modify ()
(initilize)
(message "%S" example)
(setcar example 2))
; M-x eval-buffer RET
(modify) ; message --> (3)
(modify) ; message --> (2)
(modify) ; message --> (2)
私は2つのことに興味があります。1つ目は、「内部」で何が起こっているのかを詳しく知ることです。なぜそれが初めて機能し、その後の呼び出しで失敗するのでしょうか。
2番目のより実用的な質問は、リストを適切に再初期化する方法ですか、またはそのようなことを行う別の一般的な方法はありますか?
私が見つけた1つの回避策は、引用リストを使用して、次のようにコンテンツを評価することです。
(setq example `(,3))
example
、変数として宣言されたことがないためsetq
、新しい変数を宣言するかのように動作する必要があると思いますが、後でinitialize
もう一度呼び出すと、新しい変数が作成され、modify
古い変数が記憶されます...いずれにせよ、これは予期される動作ではsetq
ありませんが、変数として以前に導入されていないものでの使用も未定義になる可能性があります。
'(3)
はリテラル値として扱われるので、一度(setcar '(3) 2)
、を行う(defvar foo '(3))
などのときに(let ((foo '(3)))
、foo
と等しい値を取得する可能性があります'(2)
。「可能性が高い」と言うのは、この動作が保証されていないためです。定数サブ式の除去(特定のケース)として知られる、インタプリタが気が向くたびに行う一種の最適化です。ですから、abo-aboが書いたのは正確な理由ではありません。これは、Cで文字列リテラルを変更するようなものです(通常は警告が生成されます)。
'(some list)
ようにeq
する'(some list)
- これまで .Thereは、一般的に目に見えて、リストを引用していること、コードが新しいリスト構造を毎回返すことLispでは保証するものではありません。一部のLisp実装では、そうなる場合もあれば、場合によってはそうなる場合もあります。他では、それは決してしません。いずれにしても、コードは実装からのそのような動作に依存してはなりません。新しいリスト構造が必要な場合はlist
、cons
または同等のものを使用してください。