3

以下代码生成从 1 到 n 的素数:

(defun prime-list(n)
  (let ((a)(b)(x (floor (sqrt n))))
    (loop for i from (floor n 6) downto 1 do
          (push (1+ (* 6 i)) a)
          (push (1- (* 6 i)) a))
    (loop while (<= (car a) x) do
          (push (car a) b)
          (setf a (remove-if #'(lambda(m)(or (= 0 (mod m (car a))) (> m n))) a)))
    (append '(2 3) (reverse b) a)))

在我看来,这部分

(setf a (remove-if #'XXX a)) 

可以替换为

(delete-if #'XXX a)

我希望这会让它更快。但是,当我进行更改时,函数现在进入无限循环并且永远不会返回。为什么?

4

3 回答 3

7

如评论中所述,您需要设置变量。

DELETE-IF主要是REMOVE-IF. REMOVE-IF返回一个新的 consed 序列,其中不包含已删除的元素。DELETE-IF可能会返回一个重复使用的序列。

如果您有一个绑定到列表的变量,您仍然需要设置结果。上面的函数返回结果,但它们没有为结果设置变量。在列表的情况下,DELETE-IF操作的结果可以是空列表,并且不可能有副作用,即可以为它设置一个变量 - 当它指向一个非空列表时。

于 2012-07-26T04:27:03.763 回答
0

我没有太多的 CL 经验,但是我在 Scheme 中做了很多工作。

在第二个版本(sans setf a)中,remove-if 表达式被求值,但它实际上并没有改变 a。loop 是 CL 中的一个宏,它只计算表达式,但不像递归函数那样使用这些表达式的结果。

因此,在第一个版本中,由于 setf 每次循环运行时 a 的值都会更改,但在第二个版本中,a 的值始终保持不变。因此 (car a) 永远不会改变并且循环永远不会终止。

我们可以在两个循环语句上比较 macroexpand 的结果:

没有 setf:

(MACROLET ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-ERROR)))
 (BLOCK NIL
  (LET NIL
   (MACROLET ((LOOP-FINISH NIL '(GO SYSTEM::END-LOOP)))
    (TAGBODY SYSTEM::BEGIN-LOOP
     (PROGN (UNLESS (< (CAR A) X) (LOOP-FINISH))
      (PROGN (PUSH (CAR A) B) (REMOVE-IF #'(LAMBDA (M) (= 0 (MOD M (CAR A)))) A)))
     (GO SYSTEM::BEGIN-LOOP) SYSTEM::END-LOOP
     (MACROLET
      ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-WARN) '(GO SYSTEM::END-LOOP))))))))) ;

使用 setf:

(MACROLET ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-ERROR)))
 (BLOCK NIL
  (LET NIL
   (MACROLET ((LOOP-FINISH NIL '(GO SYSTEM::END-LOOP)))
    (TAGBODY SYSTEM::BEGIN-LOOP
     (PROGN (UNLESS (< (CAR A) X) (LOOP-FINISH))
      (PROGN (PUSH (CAR A) B)
       (SETF A (REMOVE-IF #'(LAMBDA (M) (= 0 (MOD M (CAR A))))) A)))
     (GO SYSTEM::BEGIN-LOOP) SYSTEM::END-LOOP
     (MACROLET
      ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-WARN) '(GO SYSTEM::END-LOOP))))))))) ;

您可以看到在第一个循环中计算了 remove-if 表达式,但没有使用它的结果。

于 2012-07-26T01:18:47.640 回答
-1

克里斯是正确的。

delete-if您可以使用代替来加快速度remove-if

于 2012-07-26T01:33:51.783 回答