14.8 递归统计多个文件中的单词数量

除了使用 while 循环,你也可以通过递归方式处理文件列表中的每一个文件。lengths-list-many-files 的递归版本简洁短小。

递归函数包含常规组成部分:继续执行判断条件、步进表达式,以及递归调用。继续执行判断条件决定函数是否需要再次调用自身——当 list-of-files 中仍有剩余元素时便会继续;步进表达式将 list-of-files 重置为自身的 CDR,最终列表会变为空;递归调用则在更短的列表上执行自身。完整的函数比这段描述还要简短!

(defun recursive-lengths-list-many-files (list-of-files)
  "Return list of lengths of each defun in LIST-OF-FILES."
  (if list-of-files                     ; do-again-test
      (append
       (lengths-list-file
        (expand-file-name (car list-of-files)))
       (recursive-lengths-list-many-files
        (cdr list-of-files)))))

简单来说,该函数先获取 list-of-files 中第一个文件的长度列表,再将其与自身在剩余文件上调用的结果拼接起来。

下面是对 recursive-lengths-list-many-files 的测试,同时分别展示在各个文件上运行 lengths-list-file 的结果。

如有需要,先加载 recursive-lengths-list-many-fileslengths-list-file,再对下列表达式求值。你可能需要修改文件路径;此处给出的路径适用于本 Info 文件与 Emacs 源码位于常规位置的情况。若要修改表达式,可将其复制到 *scratch* 缓冲区编辑后再求值。

结果会显示在 ‘’ 之后。(这些结果基于 Emacs 22.1.1 版本的文件,其他版本的 Emacs 文件可能产生不同结果。)

(cd "/usr/local/share/emacs/22.1.1/")

(lengths-list-file "./lisp/macros.el")
     ⇒ (283 263 480 90)

(lengths-list-file "./lisp/mail/mailalias.el")
     ⇒ (38 32 29 95 178 180 321 218 324)

(lengths-list-file "./lisp/hex-util.el")
     ⇒ (82 71)

  (recursive-lengths-list-many-files
   '("./lisp/macros.el"
     "./lisp/mail/mailalias.el"
     "./lisp/hex-util.el"))
       ⇒ (283 263 480 90 38 32 29 95 178 180 321 218 324 82 71)

recursive-lengths-list-many-files 函数输出了我们需要的结果。

下一步是将列表中的数据整理为适合图表展示的形式。