摘自 《Lisp语言- 陈光喜》
一、函数
1、defun
Common Lisp中定义函数使用defun来完成。通常需要3个以上的参数:函数名、参数表、函数体。例如:
>(defun area(r)
(* PI r r))
>AREA
在Common Lisp中,每个函数的地位都是一样的,没有所谓的main函数。函数调用的求值规则就是表达式求值规则:
首先对每个参数从左到右求值;其次将这些已经求值的参数作为运算符函数的参数进行函数调用求值;函数的返回值由该函数最后一个求值表达式的值给出。
例1,定义求笛卡尔积的函数
CL-USER> (defun discarets(list1 list2)
(let ((a nil)(rst nil))
(dolist (v list1 rst)
(dolist (u list2)
(setf a (list u v)
rst (cons a rst))))))
DISCARETS
2、函数对象
在 Lisp 中,函数与符号、表、字符串等都是对象。Lisp 提供的 function 函数可以给出函数的关联属性。
例如:
CL-USER> (function eq)
#<Compiled-function EQ #x100097DEF>
function 函数可以简写为#’。例如,
CL-USER> #' cons
#<Compiled-function CONS #x1000D88DF>
> (apply #'area '(2))
12.5663706143592
> (apply #'* '(1 2 3 4))
24
> (funcall #'area 2)
12.5663706143592
> (funcall #'* 1 2 3 4)
24
defun 用于创建一个函数,并给出一个函数名。事实上,在 Lisp 中函数未必需要函数名。早期版本的 Lisp 提供lambda 表达式来实现函数定义。
Lambda 表达式是一个表,包含符号 lambda,然后是一个参数表,最后是 0 个或多个表达式的函数体。在 Lisp 中采用如下形式描述一个函数: (lambda (p1p2 ... pn) e) 其中, pi为原子,在函数中称之为参数,e 是表达式,也就是函数体。
调用一个函数的方式如下:((lambda (p1p2 ... pn) e) a1a2 ... an)其中 ai为表达式,按照惯例称为实参。整个函数的调用过程如下:每一个表达式 ai(实参)先求值,然后再将这些实参代入 e 中求值,最后的结果即为整个表达式的返回值。
2) Lisp 没有函数与程序之分。函数由前缀表达式组成。表达式可以是原子,也可以是表。通常表的第一个元素是操作符,其余元素是它的参数。前缀表达式意味着参数个数是任意的。
3) 函数调用时参数表从左至右求值。Quote 将参数原样返回。
4) Lisp 程序就是表,容易实现写程序的程序。
5) if 和 cond 用于条件表达式。nil 是假,从逻辑上讲,不是 nil 的都是真。
6) do 和 dolist 用于循环。Defun 用于定义用户函数。函数用 lambda 表达式来实现。函数也是Lisp 对象,可以作为函数的参数。
7) 递归函数是调用自身的函数,它是 Lisp 的基本特征。递归类似于数学归纳法。
8) 基本输入输出用 read 和 format 实现,可以使用 let 定义局部变量;defparameter 定义全局变量;setf 用于变量赋值