功能
(defun test-1 ()
(format t "~%Enter number less or equal 1: ")
(let ((x (read)))
(when (> x 1)
(format t "~%Error!")
(test-1))
x))
当输入 2 后跟 1 时,计算结果为 2,而函数
(defun test-2 ()
(format t "~%Enter number less or equal 1: ")
(let ((x (read)))
(cond ((> x 1)
(format t "~%Error!")
(test-2))
(t x))))
当输入 2 后跟 1 时,计算结果为 1,这是预期的。我不明白为什么 test-1 的行为不同。
第一个版本不是尾递归,而第二个版本是。第一个版本将返回第一次调用
*standard-input*
时从 read
读取的值。第二个将回答上次调用 read
产生的值。尝试 trace
了解行为差异。
第一个版本中使用的
let
形式具有基本形状
(let (...)
(when ... (test-1))
x). ;; <--- This is the expression that determines the result in the first variant
let
主体在这里充当隐式progn
,即,由于主体中when
之后还有形式,因此when
因其副作用而被执行,但其结果未被使用。
要使第一个版本尾递归,请使用类似的方法
(defun test-1 ()
(format t "~%Enter number less or equal 1: ")
(let ((x (read)))
(if (> x 1)
(progn
(format t "~%Error!")
(test-1))
x))
在test-1中,每次输入>1的数字时,都会递归调用该函数并将调用放入堆栈中。当最后一个值<= 1 is entered it returns x. But note that the return value x is outside the when function, so the value of the calling function replaces the value of the called function. Therefore the result is the first value that you entered. In test-2 on the other hand, when a value <= 1 is entered, it calls the function recursively and the returned value is not replaced by any other value, but it's passed to the calling function. Therefore it returns the first entered value which is <= 1.