我们已经完成了函数定义的各个部分,现在需要将它们整合起来。
首先是 while 表达式的内容:
(while (<= row-number number-of-rows) ; true-or-false-test (setq total (+ total row-number)) (setq row-number (1+ row-number))) ; incrementer
配合 let 表达式的变量列表,这几乎完成了函数体的定义。但还需要最后一个细节,其作用较为微妙。
最后一步是在 while 表达式之后单独一行放置变量 total。否则整个函数的返回值将是 let 体内最后一个被执行表达式的值,也就是 while 的返回值,而它永远是 nil。
这一点初看并不明显。看起来似乎递增表达式是整个函数的最后一个表达式,但该表达式其实是 while 体的一部分,是符号 while 开头的列表中的最后一个元素。而且整个 while 循环又是 let 体内的一个列表。
函数的整体结构大致如下:
(defun name-of-function (argument-list)
"documentation..."
(let (varlist)
(while (true-or-false-test)
body-of-while... )
... )) ; Need final expression here.
由于 let 除了被包含在 defun 内外没有嵌入其他列表,因此 let 的执行结果就是 defun 的返回值。但如果 while 是 let 表达式的最后一个元素,函数将永远返回 nil,这并不是我们想要的结果。我们希望返回的是变量 total 的值。只需将该符号作为 let 开头列表的最后一个元素即可实现:它会在列表前面的元素执行完毕后被求值,此时它已经被赋予了正确的总数。
把 let 开头的列表写在一行上会更容易理解。这种格式可以清楚地看到,变量列表(varlist)和 while 表达式是 let 列表的第二、第三个元素,而 total 是最后一个元素:
(let (varlist) (while (true-or-false-test) body-of-while... ) total)
将所有部分组合后,triangle 函数的定义如下:
(defun triangle (number-of-rows) ; Version with ; incrementing counter. "Add up the number of pebbles in a triangle. The first row has one pebble, the second row two pebbles, the third row three pebbles, and so on. The argument is NUMBER-OF-ROWS."
(let ((total 0)
(row-number 1))
(while (<= row-number number-of-rows)
(setq total (+ total row-number))
(setq row-number (1+ row-number)))
total))
执行该函数定义安装 triangle 后,你可以进行测试。下面是两个示例:
(triangle 4) (triangle 7)
前四个数字之和为 10,前七个数字之和为 28。