は、私は二つのリスト(setq x '(1 2 3))
と(setq y (list 1 (cadr x) 3)
を持っていると思ったが、私は(setf (cadr x) 'a)
後(cadr y)
は私にA
ない2
を与えるだろうと言っているよう(cadr y)
が実際に(cadr x)
を指すように望んでいたと言います。それを行う方法はありますか?部分的に共有データ構造のCommon Lisp
答えて
x
が(list 1 2 3)
である代わりに、代わりにリテラルが標準で定義されていない結果をもたらすからです。
あなたの例では、共有リスト構造はまったくありません。あなたが持っているものは、同じ値を指す異なるリスト構造です。 (setf (cadr x) 'a)
は、x
というリスト構造を変更し、異なる値を指しています。値2
を別のものに変更しません。結果は1つの場所だけを変更したということです。
(let ((tmp (list 2 3)))
(defparameter *x* (cons 1 tmp))
(defparameter *y* (cons 'a tmp)))
*x* ; ==> (1 2 3)
*y* ; ==> (a 2 3)
;; the cdr of both are the same
(eq (cdr *x*) (cdr *y*)) ; ==> t
;; mutating the cadr changes both since both list use the same cons
(setf (cadr *x*) 'q)
*x* ; ==> (1 q 3)
*y* ; ==> (a q 3)
共有可変オブジェクト
:共有リスト構造では、そのリスト内の同じcons
を持っているいくつかのリストが短所が変異されたときに、新しい値を取得する効果があります
変更可能な文字列のように、変更可能なオブジェクトの値がある場合は、cons
を変更する代わりに、それを直接変更することができます。
(let ((ele (copy-seq "ni"))) ; make ele mutable
(defparameter *x* (list ele 1 2 4))
(defparameter *y* (list 5 6 ele 7)))
*x* ; ==> ("ni" 1 2 4)
*y* ; ==> (5 6 "ni" 7)
;; mutating the string value, not the reference to the value
(setf (aref (car *x*) 1) #\o)
*x* ; ==> ("no" 1 2 4)
*y* ; ==> (5 6 "no" 7)
あなたはすべてのタイプのためにそれを一般化するボックスを作ることができます:あなたは本当に起こることボックスは、我々は変更する値を持つ構造であることで気づくけどとして
(defstruct box (data))
(let ((ele (make-box :data "ni"))) ; make ele mutable
(defparameter *x* (list ele 1 2 4))
(defparameter *y* (list 5 6 ele 7)))
*x* ; ==> (#s(box :data "ni") 1 2 4)
*y* ; ==> (5 6 #s(box :data "ni") 7)
;; mutating the string value, not the reference to the value
(setf (box-data (car *x*)) 10)
*x* ; ==> (#s(box :data 10) 1 2 4)
*y* ; ==> (5 6 #s(box :data 10) 7)
リストが指します同じ箱。
これは一般的に不可能です。
は、次の2つのリストを持っている想像:
CL-USER 11 > (sdraw (list 1 2 3))
[*|*]--->[*|*]--->[*|*]--->NIL
| | |
v v v
1 2 3
CL-USER 12 > (sdraw (list 'a 'b 'c))
[*|*]--->[*|*]--->[*|*]--->NIL
| | |
v v v
A B C
あなたはコンス・セルとの間のリンクを表しているだろうか?最初のリストの2番目のコンスセルのCARを変更すると、2番目のコンスセルのCARも変更されます。
一方の方法は、マシンの下に変更を検出し、何かをするメカニズムを持つことです。 Lispマシンではメモリの場所を見ることができますが、単純なCommon Lispではこれは不可能です。
また、CADRを変更して、マークされた特定のコンセルの変更を検出することができます。繰り返しますが、これは単純なCommon Lispではありません。したがって
? (setf l1 (list 1 2 3))
(1 2 3)
? (watch (cdr l1))
(2 3)
? (setf (cadr l1) 'a)
> Error: Write to the CAR of watched cons cell (2 3)
> Faulting instruction: #<X86-DISASSEMBLED-INSTRUCTION (movq (% rsi) (@ 5 (% rdi))) #x302000E1EA0D>
> While executing: CCL::SET-CADR, in process Listener(4).
1がコンスセルが変更されたことを検出し、その変化に何かをするだろう条件ハンドラを呼び出すことができます。
エクスカーション
Clozure CLはコンスセルを監視する機構を備えています...
- 1. 共通lispとemacs lispの構造の相違点
- 2. Clojureの構造共有
- 3. Scalaの構造共有リスト
- 4. Scheme/Common Lisp/Clojureの自動微分ライブラリ
- 5. Common Lispのクラスイントロスペクション
- 6. Common Lispの効率的なcollect関数
- 7. Common Lisp Memory Issues
- 8. Common Lisp用ベクターグラフィックスライブラリ
- 9. ステップEval Common Lisp
- 10. Common Lispでデータを圧縮するストリームインターフェイス
- 11. コロン構文、Common Lispの変数の前にコロンは、何を意味しているCommon Lispの
- 12. perlとcppの間のデータ構造の共有
- 13. Lispのメンバーと構造体
- 14. ソースコードlisp(Common Lisp、Scheme、Clojure)の美人
- 15. Common Lisp let関数
- 16. Common Lispラムダ式エラー
- 17. Common Lisp Unbound変数
- 18. common lisp function/macro aliases
- 19. Common Lisp vs. MacLisp/InterLisp
- 20. Common Lisp並列プログラミング
- 21. Common Lispグラフィカルユーザインタフェース開発
- 22. 構造体と共有リソースの静的クラス
- 23. C++部分構造ビットフィールドサイズ
- 24. マルチレベルモデリングのための共分散構造
- 25. d2:部分的に既知の構造の不変性
- 26. 部分的にファイルシステムをバックアップしているデータ構造ですか?
- 27. 明示的なデータ構造と明示的なデータ構造
- 28. Common Lisp:ディレクトリの作成
- 29. Common Lisp用のレクサーとパーサージェネレータ
- 30. Common Lispのパッケージ定義
リストの末尾はすべて共有されています。 2番目の要素だけを共有する必要がある場合は、変更可能なオブジェクトに値をラップする必要があります。 – jkiiski
@jkiiskiもし、その値が変更可能な文字列のように変更できるのであれば、値を変更することはできますが、* shared structure *の場合は両方のリストに同じconsを持つ必要があります。しかし、テールである必要はありません。あなたは* y * '(list tmp tmp)'を作ることができ、最後は '((q 3)(q3))'となります。 – Sylwester
はい、具体的な例では尾全体が共有されています。共有構造を必要とするのか、リストの真ん中に単一の共有オブジェクトしか持たないのかは、完全にはっきりしません。 – jkiiski