重用复杂数据结构

有时,我们会希望函数是和其他语言中的函数一样的运行,即在不修改传入参数的情况下返回个新值,而有时,我们又想让函数重用或在数据的原有基础上进行修改 —— 想想 [append](http://www.lispworks.com/documentation/HyperSpec/Body/f_append.htm)[nconc](http://www.lispworks.com/documentation/HyperSpec/Body/f_nconc.htm) 之间的区别吧。或者是 C 语言函数中的传值与传址。

要想实现上面所说的功能,可以使用可选(关键词)参数。如:假设需要实现一个名为 complex-matrix-stuff 的函数,该函数有两个参数 m1m2,然后函数会计算出矩阵 m1m2 运算结果并返回所得矩阵的大小,也就是说,在调用函数时将会由 (make-appropriate-result-matrix-for m1 m2) 创建一个空矩阵用来存储结果。

标准的教科书式的实现方法看起来和下面的差不多:

  1. (defun complex-matrix-stuff (m1 m2)
  2. (let ((result (make-appropriate-result-matrix-for m1 m2)))
  3. ;; ... compute storing the results in RESULT
  4. result))

然后就可以这样调用:

  1. (setq some-matrix (complex-matrix-stuff A B))

但为什么不写成下面这种形式呢?

  1. (defun complex-matrix-stuff (m1 m2
  2. &optional
  3. (result
  4. (make-appropriate-result-matrix-for m1 m2)))
  5. ;; ... compute storing the results in RESULT
  6. result)

现在就有两种方法了,而且依然可以像之前一样使用:

  1. (setq some-matrix (complex-matrix-stuff A B))

但也可以直接将结果赋给已经存在的变量:

  1. (complex-matrix-stuff A B some-appropriate-matrix-I-built-before)

或者这样:

  1. (setq some-other-matrix
  2. (complex-matrix-stuff A B some-appropriate-matrix-I-built-before))

得到的结果是一样的:

  1. * (eq some-other-matrix some-appropriate-matrix-I-built-before)
  2. T

合并新的序列时用 ADJUST-ARRAY 而不是 SUBSEQ

CL 中大部分对序列操作的函数都可以使用 startend 关键字,因此,可以不创建子字符串就进行操作。即,不要像下面这样:

  1. (count #\a (subseq long-string from to))

而是要这样使用:

  1. (count #\a long-string :start from :end to)

上面这种做法得到的结果与之前的是一样的,但不会创建不必要的中间子序列。

然而,有时创建新的数据无法避免。这时就可以将字符串当作是哈希表的关键词。当查找的键是另一个字符串的子串时,可以像下面这样:

  1. (gethash (subseq original-string from to)
  2. hash-table)

但没必要这么做。可以创建一个可变字符串,然后通过 [adjust-array](http://www.lispworks.com/documentation/HyperSpec/Body/f_adjust.htm)对该字符串进行重用:

  1. (let ((substring (make-array 0
  2. :element-type 'character
  3. :displaced-to ""
  4. :displaced-index-offset 0)))
  5. ;; more code
  6. (gethash
  7. (adjust-array substring (- to from)
  8. :displaced-to original-string
  9. :displaced-index-offset from)
  10. hash-table)
  11. ;; even more code
  12. )