11.1.1 使用 while 循环和列表

控制 while 循环的常见方法是测试列表是否包含任何元素。如果包含元素,则循环将继续;但如果不包含元素,则循环结束。由于这是一种重要的技术,我们将创建一个简短的示例来说明它。

测试列表是否包含元素的一种简单方法是评估列表:如果没有元素,它是一个空列表,将返回空列表 (),这是 nil 或 false 的同义词。另一方面,具有元素的列表在评估时将返回这些元素。由于Emacs Lisp认为任何非 nil 的值都为真,因此返回元素的列表在 while 循环中将测试为真。

例如,您可以通过评估以下 setq 表达式将变量 empty-list 设置为 nil

(setq empty-list ())

在评估了 setq 表达式之后,您可以以通常的方式评估变量 empty-list,即将光标放在符号后面,然后键入 C-x C-e;在您的回显区域中将显示 nil

empty-list

另一方面,如果将变量设置为具有元素的列表,则在评估变量时将显示该列表,如通过评估以下两个表达式所示:

(setq animals '(gazelle giraffe lion tiger))

animals

因此,要创建一个 while 循环,测试列表 animals 中是否有任何项,循环的第一部分将被编写为:

(while animals
       …

while 测试其第一个参数时,变量 animals 被评估。它返回一个列表。只要列表具有元素,while 将认为测试的结果为真;但当列表为空时,它将认为测试的结果为假。

为防止 while 循环无限运行,需要提供某种机制以最终清空列表。一个常用的技术是在 while 表达式的后续形式中之一将列表的值设置为列表的 CDR。每次评估 cdr 函数时,列表都会变得更短,直到最终只剩下空列表。此时,while 循环的测试将返回假,while 的参数将不再被评估。

例如,将绑定到变量 animals 的动物列表可以通过以下表达式设置为原始列表的 CDR

(setq animals (cdr animals))

如果您已经评估了前面的表达式,然后评估此表达式,您将在回显区域中看到 (giraffe lion tiger)。如果再次评估表达式,将显示 (lion tiger)。如果再次评估它,(tiger) 将出现,然后是空列表,由 nil 表示。

使用 cdr 反复使真或假测试最终测试为假的 while 循环的模板如下:

(while test-whether-list-is-empty
  bodyset-list-to-cdr-of-list)

这个测试和使用 cdr 的功能可以放在一起,形成一个函数,该函数遍历列表并在各自的行上打印列表的每个元素。