Google Common Lisp风格指南说Avoid modifying local variables, try rebinding instead
这是什么意思?重新绑定在那句话中意味着什么?
答案 0 :(得分:9)
这意味着您应该创建新变量而不是更改旧变量的值。例如,让我们采用以下代码:
(defun foo (x)
(when (minusp x)
(setq x (- x)))
do something with x)
相反,应该创建一个新的绑定并使用该绑定:
(defun foo (x)
(let ((xabs (if (minusp x)
(- x)
x)))
do something with xabs)
这样做的原因是你总是知道变量包含什么,因为它永远不会改变。如果您想要新值,只需使用包含该新值的变量。
现在您可能会问为什么这么重要?嗯,有些人比其他人更喜欢这个。特别是那些喜欢强调Lisp功能方面的人会提倡这种风格。但是,无论偏好如何,始终能够依赖变量不会改变的事实是非常有用的。以下是一个重要的例子:
(defun foo (x)
(let ((function #'(lambda () (format t "the value of x is ~a~%" x))))
(when (minusp x)
(setq x (- x)))
(other-function x)
function))
然后,FOO
的返回值是一个函数,当使用print调用x
的值时。但是,该值将是函数后面x
的值,即绝对值。如果功能大而复杂,这可能会非常令人惊讶。
答案 1 :(得分:4)
我不太清楚Common Lisp如何在Common Lisp中做到这一点,所以我在下面的示例中使用Scheme。假设您正在编写一个函数来返回数字的阶乘。这是对该函数的“修改局部变量”方法(您必须定义自己的while
宏,但这并不难):
(define (factorial n)
(define result 1)
(while (> n 0)
(set! result (* result n))
(set! n (- n 1)))
result)
这是该函数的“重新绑定局部变量”方法:
(define (factorial n)
(let loop ((n n)
(result 1))
(if (zero? n)
result
(loop (- n 1) (* result n)))))
在这种情况下,每次调用loop
时都会使用新值重新绑定。可以使用do
宏来编写相同的函数(顺便说一句,它也使用重新绑定,而不是修改,至少在Scheme中):
(define (factorial n)
(do ((n n (- n 1))
(result 1 (* result n)))
((zero? n) result)))