在Common Lisp循环中定义局部变量

时间:2019-05-12 00:05:19

标签: loops variables common-lisp

我想知道是否有一种方法可以在Common Lisp loop构造中引入一些局部变量,而无需对其进行任何自动递增-就像避免使用let的快捷语法一样在循环之外。

1 个答案:

答案 0 :(得分:10)

我们将从简单开始。如果让循环对任何累加单词执行某些操作,则只需命名绑定即可创建绑定。在这里,我进行了两个绑定oddsevens,因为我希望返回两个值,而counting是Loop for black belts中所描述的动词之一,当然还有CLHS loop specification中所描述的动词之一:

(loop :for num :in '(1 3 5 6 3 3)
      :counting (oddp num) :into odds
      :counting (evenp num) :into evens
      :finally (return (values odds evens)))
; ==> 5 
; ==> 1

在文档中也描述了更通用的方式是使用with子句:

(loop :with odds := 0 :and evens := 0
      :for num in '(1 3 5 6 3 3)
      :if (oddp num) :do (incf odds)
      :else :do (incf evens)
      :finally (return (values odds evens)))
; ==> 5 
; ==> 1

您已经知道for e = value then new-value了,因为它可以逐步执行,但是我将其添加到此处以供完成。请注意,顺序很重要:

(loop :for odds := 0 :then (if (oddp num) (1+ odds) odds)
      :for evens := 0 :then (if (evenp num) (1+ evens) evens)
      :for num :in '(1 3 5 6 3 3)
      :finally (return (values odds evens)))
; ==> 5 
; ==> 1

最后一个例子是函数中有&aux个元素。它创建let*绑定而没有let*和缩进。通常,这是一个真正的选择:

(defun count-odds (list &aux (odds 0) (evens 0))
  (loop :for num in list
        :if (oddp num) :do (incf odds)
        :else :do (incf evens))
  (values odds evens))

请注意,我们不需要使用finally,因为更改后的绑定在loop之外可用

知道CL可能比我想念的还要多,但这是我使用的那些。