对于autolisp, 常见的一个说法就是autolisp是lisp语言的一种方言. 严格来说, 这种说法是不准确的, 因为autolisp缺少了lisp语言最引以为傲的macro宏, 连宏都没有自然是不能算作lisp的, 顶多算是 lisp-like.

除了没有宏, autolisp还砍了lisp的不定长形参的这个特性, 所有的用户自定义函数的形参个数都是固定的, 不允许定义带有可选形参的用户函数. autolisp倒是内置了一些具有不定长形参的函数, 比如and/or之类的. 说是函数, 其实它们是special form, 因为它们的求值策略不同于普通函数, 但是autodesk用的术语就是function, 所以这里也用函数来称呼它们.

当然了, 并不是求值策略异于普通函数就一定是special form, 也可以是macro, 因为autolisp没有macro, 所以这些函数就只能是special form了.

foreachrepeat , 就是两个很典型的 special form .

foreach的用法是这样的, (foreach e lst body), 其中, lst 是一个 list , elst 的某个元素, body 是一些对 e 进行操作的表达式. 也就是说, foreach 提供的是对list元素进行遍历操作的功能.

之所以说 foreach 不同于普通函数, 是因为 (foreach e lst body)lst 是单次求值的, 仅仅在循环开始前求值1次, 循环开始之后不会再次对它进行求值, 无论要循环多少次都是如此的. 这种行为, 就是典型的macro的行为, 先执行宏展开再执行展开后的表达式.

while 就不是这样的, (while pred body)pred 在每个循环当中都是要单独求值的, 而不是在循环开始前仅仅求值1次.

foreach 有类似表现的, 还有 repeat . (repeat n body)n 也是单次求值的, 仅仅在循环开始之前求值1次, 循环开始之后不会再次对它进行求值.

啰嗦了这么多, 搞清楚了 foreach 和 repeat 的特殊性, 有什么意义呢?

意义就在于有可能提高代码的运行性能. 因为autolisp是fp函数式编程语言, 任何表达式都有返回值, 这就导致代码往往可以写得十分随意, 可以随意到看不出来判断/循环之类的控制结构. 但是, 我们又无法控制代码的求值策略, 每个塞进去的入参都会被求值, 先求值再扔到函数里边, 这就可能导致多次重复求值的情况. 一旦出现了这种情况, 就意味着平白无故的性能损失. 通常, 我们可以使用局部变量做"中转", 可是, 这样一来又显得不那么fp了.

所以, 搞清楚内置函数(special form)的求值策略就很有必要了.