在 Common Lisp 中定义全局函数要使用defun表达式。
这个表达式的第一个参数是形参列表(空列表表示该函数没有形参)。
其后是一个可选的文档字符串(见下文),然后是零个或多个表达式,它们构成函数的“函数体”。
函数可以有零个或多个形参。
(defun no-args () (+ 1 1))
(defun add-one (x) (1+ x))
(defun add-nums (x y) (+ x y))
调用函数的方式是求值一个表达式:以指定该函数的符号作为表达式的第一个元素,其余元素则是传给该函数的实参(如果有的话)。
函数求值得到的值,就是函数体中被求值的最后一个表达式的值。 所有函数都会求值得到一个值。
(add-nums 2 2) ;; => 4
函数还可以选择性地带一个文档字符串(也叫 “docstring”)。
如果提供了它,它位于形参列表之后、函数体之前。
文档字符串可以通过documentation获取。
(defun add-nums (x y) "Add X and Y together" (+ x y))
(documentation 'add-nums 'function) ;; => "Add X and Y together"
;; Note that if one provides a docstring but fails to provide a body
;; then the docstring is interpreted by Common Lisp as the body, not
;; the docstring
(defun no-body ())
(no-body) ;; => NIL
(defun mistake () "This is not a docstring")
(mistake) ;; => "This is not a docstring"
(documentation 'mistake 'function) ;; => NIL
Lisp 外星人 Lilly 又回来啦,这次要做更多的菜!这一次,他们要制作 Lisp 外星千层面,这道菜和人类的千层面并非完全不同。
Lilly 需要有人帮忙写几个函数,用来算出千层面的烹饪时间。每个函数都要有良好的文档,这样 Lilly 才不会忘记每个函数是做什么的。
你能帮 Lilly 写几个函数,帮他们算出千层面的烹饪时间吗?
定义 expected-time-in-oven 函数,它不接收任何形参,返回千层面应该在烤箱里待多少分钟。按照 Lisp 外星人的传统(就像 Lilly 的“父母单位”以前做饭那样),以分钟为单位的预期烤箱时间是 337:
(expected-time-in-oven) ;; => 337
定义 remaining-minutes-in-oven 函数,它接收千层面实际已在烤箱里待的分钟数作为形参,并根据上一个任务中得到的、以分钟为单位的预期烤箱时间,返回千层面还需要在烤箱里待多少分钟。
(remaining-minutes-in-oven 100) ;; => 237
定义 preparation-time-in-minutes 函数,它接收 Lilly 给千层面加的层数作为形参,并返回 Lilly 准备千层面花了多少分钟,假设每一层需要 19 分钟来准备。
(preparation-time-in-minutes 3) ;; => 57
定义 elapsed-time-in-minutes 函数,它接收两个形参:第一个形参是 Lilly 给千层面加的层数,第二个形参是千层面已在烤箱里待的分钟数。这个函数应该返回 Lilly 烹饪千层面所花的分钟数,也就是准备时间(分钟)与千层面此刻已在烤箱里待的分钟数之和。
(elapsed-time-in-minutes 3 100) ;; => 157