下面的代码生成从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)我希望这能让它更快。然而,当我做了这样的更改时,函数现在进入了无限循环,并且再也不会返回。为什么?
发布于 2012-07-26 12:27:04
正如注释中所提到的,您需要设置变量。
DELETE-IF主要是REMOVE-IF的破坏性版本。REMOVE-IF返回一个新的consed序列,它不包含被删除的元素。DELETE-IF可能会返回一个重复使用的序列。
如果你有一个绑定到列表的变量,你仍然需要设置结果。上面的函数返回结果,但它们不会将变量设置为结果。在列表的情况下,DELETE-IF操作的结果可以是空列表,并且不可能有副作用,即当它指向非空列表时,可以将变量设置为该列表。
发布于 2012-07-26 09:18:48
我没有太多的CL经验,但我在Scheme中做了很多工作。
在第二个版本(sans setf a)中,remove-if表达式被求值,但它不会实际更改a。循环是CL中的一个宏,它只计算表达式,但不像递归函数那样使用这些表达式的结果。
因此,在第一个版本中,由于setf的原因,每次循环运行时,a的值都会改变,但在第二个版本中,a的值始终是恒定的。因此(car a)永远不会改变,循环也永远不会终止。
我们可以比较这两个循环语句的宏扩展结果:
不使用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-26 09:33:52
克里斯是对的。
你可以用delete-if代替remove-if来提高速度
https://stackoverflow.com/questions/11660804
复制相似问题