2

編集: 解決策は、最初の (let...) 形式で '(1) を (list 1) に置き換えることです。これは、リテラル データを変更しようとしていたためです。助けてくれてありがとう!(私は賛成票を投じますが、明らかに15の評判が必要です...)

これは、このサイトでの私の最初の投稿です。

今日、いくつかのProject Eulerの問題を解決していたところ、Common Lisp で (少なくとも私にとっては) 予期しないリストの並べ替え動作に遭遇しました。

数値 x の適切な約数をすべて見つける関数があります。

(defun divisors (x)
    "Finds all of the proper divisors of x."
    (let ((sq (sqrt x)) (divs '(1)))
        (when (integerp sq) (push sq divs))
        (loop for i from 2 to (1- (floor sq)) do
        (let ((div (/ x i)))
            (when (integerp div)
                (push i divs)
                (push div divs))))
    divs))

この機能はうまく機能します。例えば:

(divisors 100)
==> (20 5 25 4 50 2 10 1)

結果のリストをソートしようとするたびに問題が発生します。

(sort (divisors 100) #'<)
==> (1 2 4 5 10 20 25 50)

まあ、それはうまくいきました。しかし、再び除数を呼び出すとどうなるでしょうか?

(divisors 100)
==> (20 5 25 4 50 2 10 1 2 4 5 10 20 25 50)

何?別の番号を試してみると...

(divisors 33)
==> (11 3 1 2 4 5 10 20 25 50)

結果のリストを並べ替えた後、前のクエリの除数は永続的です。関数を再コンパイルすると、結果のリストを再度並べ替えるまでエラーは発生しません。関数定義のどこかでめちゃくちゃになったと思いますが、私は Lisp にかなり慣れていないので、エラーを見つけることができません。ネストされた (let...) フォームの問題でしょうか?

前もって感謝します!

4

2 に答える 2

9

よく聞かれます。

リテラル データを変更しました。新しいデータを作成する必要があります。関数 LIST または関数を使用して、コピーを作成します。

于 2012-04-14T17:33:40.063 に答える
3

レイナーは正しいです。明らかでない場合は、次の変更でコードを修正できます。

(let ((sq (sqrt x)) (divs (list 1)))
于 2012-04-14T17:42:13.753 に答える