Common Lisp: is delete-if the same as setf + remove-if?

女生的网名这么多〃 提交于 2019-12-06 01:45:49

As mentioned in the comments, you need to set the variable.

DELETE-IF is mostly a destructive version of REMOVE-IF. REMOVE-IF returns a freshly consed sequence, which does not contain the removed elements. DELETE-IF may return a sequence which is reused.

If you have a variable, which is bound to a list, you still need to set the result. Above functions return results, but they don't set variables to the result. In case of a list, the result of a DELETE-IF operation can be the empty list and there is no way the side effect can be, that a variable can be set to it - when it was pointing to a non-empty list.

I don't have very much CL experience, but I've done a lot of work in Scheme.

In the second version (sans setf a) the remove-if expression is evaluated, but it does nothing to actually change a. loop is a macro in CL, it just evaluates expressions, but doesnt use the results of those expressions like a recursive function would.

So in the first version, the value of a is changed each time the loop runs due to the setf, but in the second, the value of a is constant throughout. Thus (car a) never changes and the loop never terminates.

we can compare the results of macroexpand on both the loop statements:

without 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))))))))) ;

with 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))))))))) ;

you can see that in the first loop the remove-if expression is evaluated, but its result isn't used.

Chris is correct.

You may speed things up by using delete-if in place of remove-if

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!