10

http://www.aiai.ed.ac.uk/~jeff/lisp/cl-pitfallsは、これを Common Lisp の落とし穴の 1 つとして述べています。

CDR を変更すると思われる破壊的な関数は、代わりに CAR を変更する可能性があります。(例: NREVERSE)

どのような予防措置をとればよいかわかりません。NREVERSE が CDR を変更する可能性があるという事実から私が取ることができる通常の予防措置は、リスト (引数) が、私の変数が後で参照する可能性のある他のリストとテールを共有しない場合にのみ NREVERSE を使用することです (戻り値を保存する変数を除く)。に)。NREVERSE が CAR を変更する可能性があるという事実から、どのような予防措置を講じるべきですか? これはどのように注意する必要がありますか?

4

2 に答える 2

12

コンテキストがないと、これを理解するのは非常に困難です。

例:

(setq list1 (list 1 2 3 4))

これで、4 つの数値のリストができました。変数list1は最初のコンスを指します。

破壊的なリバースを見ると、コンスセルを変更する可能性のある操作について話しています。このリストを元に戻す方法はいくつかあります。

たとえば、コンスセルを取り、それらを逆にすることができます。最初のコンスセルは最後です。次に、そのコンス セルの cdr を に変更する必要がありNILます。

CL-USER 52 > (setq list1 (list 1 2 3 4))
(1 2 3 4)

CL-USER 53 > (nreverse list1)
(4 3 2 1)

ここで、変数list1は同じコンス セルを指していますが、その cdr は変更されています。

CL-USER 54 > list1
(1)

変数が反転したリストを指していることを確認するために、プログラマは変数を更新し、nreverse操作の結果に設定する義務があります。list1最後の短所を示す観察可能な結果を​​利用したくなるかもしれません。

上記は、Lisp 開発者が通常期待するものです。リバースのほとんどの実装は、そのように機能するようです。しかし、ANSI CL 標準では、どのようnreverseに実装する必要があるかは指定されていません。

では、代わりに CAR を変更するとはどういう意味でしょうか?

の代替実装を見てみましょうnreverse:

(defun nreverse1 (list)
  (loop for e across (reverse (coerce list 'vector))
        for a on list do
        (setf (car a) e))
  list)

上記の関数は、コンス セルのチェーンをそのままにしておきますが、carを変更します。

CL-USER 56 > (setq list1 (list 1 2 3 4))
(1 2 3 4)

それでは、新しいバージョンのnreverse1.

CL-USER 57 > (nreverse1 list1)
(4 3 2 1)

CL-USER 58 > list1
(4 3 2 1)

これで違いがわかります。list1まだリスト全体を指しています。

要約: さまざまな実装がnreverse可能なことに注意する必要があります。変数が最後のコンスを指す通常の動作を悪用しないでください。の結果を使用するだけでnreverse、すべて問題ありません。

補足: 2 番目のバージョンはどこで使用された可能性がありますか?

Lisp マシンでの Lisp 実装の中には、コンパクトなベクトルのようなリストの表現が可能だったものがあります。そのような Lisp 実装でそのようなリストを nreverse する場合、実装者は効率的な vector-like nreverse を提供できます。

于 2013-08-18T17:56:14.560 に答える