Common Lisp: what's the best way to loop throu

2019-06-19 01:18发布

问题:

Sometimes I need to loop through consecutive pairs in a list. The way I do it right now is

(loop for x on lst while (not (null (cdr x)))
       (do something on (car x) and (cadr x)))

I'm wondering if there is a better/built-in way to do this.

The reason I need this is sometimes I want, e.g. some function that add consecutive pairs

(1 2 3 4 5) ----> (3 5 7 9)

Is there any built-in function like reduce which allow me to get this?

回答1:

AFAIK, there isn't a built-in function to do what you want. You could try to put something together with maplist, but my first instinct would be to reach for loop too.

Just a couple of notes on what you've got there though. First, (not (null foo)) is equivalent to foo in CL, since a non-NIL value is treated as t by boolean operations. Second, loop can destructure its arguments, meaning you can write this more elegantly as

(loop for (a b) on lst while b
      collect (+ a b))

The maplist version would look something like

(maplist 
   (lambda (rest) 
     (when (cdr rest) 
        (+ (first rest) (second rest)))
   lst)

which I consider less readable (this would also return NIL as the last element of its result, rather than just ending before that).



回答2:

I believe Paul Graham has a function named map-tuple in OnLisp which does this. It can move down the list by cdr, cddr, or however you please. Here is a commented version of it. It uses his anaphoric if macro aif.

(defun map-tuple (someList f &optional (by #'cdr))
 "(map-tuple someList f &optional (by #'cdr))
   f is a function that takes two args, returns one val (maybe)
   the map-tuple will collect all non-nil results in a list.
    example: 
(map-tuple '(1 2 3 4 5 6) (lambda (a b) (format T \"a: ~A b:~A~%\" a b)) #'cdr) 
a: 1 b:2
a: 2 b:3
a: 3 b:4
a: 4 b:5
a: 5 b:6
a: 6 b:NIL

(map-tuple '(1 2 3 4 5 6) (lambda (a b) (format T \"a: ~A b:~A~%\" a b)) #'cddr) 
a: 1 b:2
a: 3 b:4
a: 5 b:6
"
  (cond ((null someList)
        nil)
    (T
       (aif (funcall f (car someList) (cadr someList))
          (cons it (map-tuple (funcall by someList) f by))
           (map-tuple (funcall by someList) f by)))))


标签: common-lisp