首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >常见Lisp:是delete-if等同于setf + remove-if吗?

常见Lisp:是delete-if等同于setf + remove-if吗?
EN

Stack Overflow用户
提问于 2012-07-26 08:43:15
回答 3查看 1.6K关注 0票数 3

下面的代码生成从1到n的质数:

代码语言:javascript
复制
(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)))

在我看来,这个角色

代码语言:javascript
复制
(setf a (remove-if #'XXX a)) 

可以替换为

代码语言:javascript
复制
(delete-if #'XXX a)

我希望这能让它更快。然而,当我做了这样的更改时,函数现在进入了无限循环,并且再也不会返回。为什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-07-26 12:27:04

正如注释中所提到的,您需要设置变量。

DELETE-IF主要是REMOVE-IF的破坏性版本。REMOVE-IF返回一个新的consed序列,它不包含被删除的元素。DELETE-IF可能会返回一个重复使用的序列。

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

票数 7
EN

Stack Overflow用户

发布于 2012-07-26 09:18:48

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

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

因此,在第一个版本中,由于setf的原因,每次循环运行时,a的值都会改变,但在第二个版本中,a的值始终是恒定的。因此(car a)永远不会改变,循环也永远不会终止。

我们可以比较这两个循环语句的宏扩展结果:

不使用setf:

代码语言:javascript
复制
(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:

代码语言:javascript
复制
(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表达式被求值,但是它的结果没有被使用。

票数 0
EN

Stack Overflow用户

发布于 2012-07-26 09:33:52

克里斯是对的。

你可以用delete-if代替remove-if来提高速度

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11660804

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档