0%

Common Lisp 语法规则

注释

;;;; 四个分号用于文件头注释
;;; 三个分号用于一大段特定代码的作用的描述
;; 某几行代码的功能性描述,注释与被注释的代码具有相同的缩进
; 用于单行注释

S-表达式

S-表达式的基本元素是列表(list)和原子(atom)。列表由括号所包围,并可包含任意数量的由空格所分隔的元素。原子是不可分割的元素。列表元素本身也可以是S-表达式。

比如(1 2 3) ,(“stf” 1 2 3),(foo 1 2 3) , (foo 1 2 3 (getMax 4 5))等都是S表达式。

常见原子类型

数字

由(数位),(.),(表示正负的+或-),(除号/),(指数标记e或d)

123 ;表示数字123
+122 ;表示正123
-122 ;表示负122
12.1 ;默认精度浮点数
121e-1 ;同一个浮点数另一种写法
121d-1 ;双精度浮点数
-5/4 ;比值-五分之四

字符串

由双引号包围的某些可见字符组成的序列,反斜杠()为转移字符,转义接下来的任意字符

例如:
“foo” 表示由f,o,o组成的字符串
“fo\o” 同一个字符串
“fo\o” 表示由f,o,,o组成的字符串
“fo\”o” 表示由f,o,”,o组成的字符串

名字

函数名和变量名是最常见的名字。几乎任何字符都可以出现在名字里,只要整个名字不被解释成一个数字,名字还可以包含句点(.),但一个合法Lisp名字不能全为句点(.)。

10个特殊的字符不能被用于名字,分别是:
开括号 ()
闭括号 []
双引号 “
单引号 ‘
反引号 `
逗号 ,
冒号 :
分号 ;
反斜杠
竖线 |

如果非用用这10个字符作为名字,则必须在字符前加入转移字符()
例如:
on\off 可以表示一个名字:on\of,但在定义和使用时应该使用完整名称
on\off。

Lisp形式的S-表达式

函数调用

(function-name argument*)

比如:
(+ 1 2) ;+号为函数名
(/ 2 (+ 1 1)) ;最外层的/是函数名,内部嵌套的+也为函数名

特殊操作符

并非所有的操作都能定义成函数。例如以下条件判断语句也可以作为S-表达式。
(if (x) (format t “yes”) (format t “no”)) ;(x)返回真,输出yes, 为假输出no

(quote S-表达式) ;只是简单返回S-表达式
以上等价于 `(S-表达式)

总结:一般特殊操作符所实现的语言特性,需要求值器作出某些特殊处理。

宏是以S-表达式为其参数的函数,并返回一个Lisp形式

宏的求值包含两个阶段:

  1. 宏形式的元素不经求值即被传递到宏函数里。且这些元素不必是标准的Lisp形式。
  2. 由宏函数所返回的形式按照正常的求值规则进行求值。

当Lisp代码被编译时,源文件的所有宏形式将被递归展开,直到代码中只有函数调用形式和特殊形式。这些无宏的代码被编译成一个FASL文件——Load函数知道如何去加载它。

真假和等价

符号NIL表示唯一的假值,除此以外的所有值都是真值T.

NIL是唯一一个既是原子又是列表的对象,因为它既可以作为假值使用,又可以作为空列表()

所以 nil, (), `() , `nil的求值结果相同
t `t的求值结果也相同

等价:

EQ:是最严格的等价判断,只有当两个对象相同时才返回T, 其它都返回nil。

EQL:相比EQ更为宽松,当两个对象表示相同的字符或数字时,即使不是相同的对象,也返回T,其它类型回退到EQ水平。
例如(EQL 1 1)返回T,但(EQL 1 1.0)则返回nil, 因为1和1.0属于不同的对象。

EQUAL 相比EQL更宽松的一点是,它将在递归上具有相同结构和内容的列表视为等价,EQUAL 也认为含有相同字符的字符串是等价的。它对于位向量和路径名也定义了比EQL更加宽松的等价性。对于所有其它类型,它回退到EQL的水平。

EQUALP比EQUAL更加宽松之外,也相似于EQUAL,在判断两个字符串等价时忽略了大小写的区别,只要表示相同数学意义的值,它们就是等价的
例如:
(EQUALP “helloworld” “HelloWorld”) 返回T
(EQUALP 1 1.0) 返回T

emacs小技巧

选中,C-M-q重新缩进整个表达式
在函数体的任何位置 通过C-c M-q来缩进整个函数体