参考: http://steve-yegge.blogspot.in/2008/01/emergency-elisp.html
http://www.gnu.org/software/emacs/emacs-lisp-intro/
Lisp中的基本概念
列表(List)是Lisp的基础,用括号标识其边界。Lisp的名称代表LISt Processing,就是处理列表的语言。因此会在Lisp代码看到层层叠叠的小括号,这种嵌套的括号表达式在Lisp中称为Forms。以下两个例子均为列表
'(this list has (a list inside of it))
(+ 2 3)
括号里面没有用括号括起来的,在Lisp中叫原子(atoms),它是不可分割的,如字符串(如”this is a text”),数字(如37,511,1729),符号(如‘+’)等,原子之间用空格隔开。
列表的运行方法:在emacs中,将光标移到列表(表达式)末尾,敲入C-x C-e. 比如上面的第一个列表执行结果将为(this list has (a list inside of it)),第二个列表执行后输出结果为5。可以看出,如果列表不带单引号,则会将第一个元素当作是函数(’+’在其它语言中可能是操作符,在 Lisp中可以认为是函数),会执行函数相应的指令,否则,会认为第一个元素只是一个普通的符号,执行结果就是列表本身。列表内部的列表也是可以单独执行的,只要把光标放到列表反括号的后面敲入C-x C-e即可,如
(+ 2 (+ 3 3 ))
将光标放到最后一个小括号上面,执行结果为6,放到最后一个小括号后面,执行结果为8。
符号除了代表一个函数(如’+’),也可表示一个值,并且这个值还可能是可变的,此时称这个符号为变量。如fill-column表示emacs自动换行的字符数.直接执行下面的变量,执行时echo area会显示70(不同的电脑显示结果不一样)。
fill-column
而如果执行
(fill-column)
则会报错,因为它并不是一个函数。
参数是指跟随在函数后面的原子或列表,如(+ 2 3)中的2和3 ,有的函数没有参数,则用空列表表示。参数还可能是字符串或变量的值,参数个数还可以是可变的
(concat “foo” “bar” “baz”)
(substring “foobar” 0 3)
(+ 2 fill-column)
(+ 3 4 5)
显示消息给用户的函数为message,如:
(message "The value of fill-column is %d." fill-column)
Lisp的注释由分号开始,直至行尾。
Lisp使用set给变量赋值,其使用方法为:
(set 'sum (+ 2 2))
由于set后面加一个飘号的使用频繁非常高,因此用了一个更简便的形式setq来代替:
(setq sum (+ 2 3)) ; setq means "set quoted"
另一个赋值是defvar,它与setq有两个区别。 1. 如果变量没有值时才会给变量赋值,否则保持变量的值不变,也就是说,defvar只用来初始化一个变量。2. defvar多一个参数——会写进文档的描述字符串。
defconst用来定义一个常量,其意义在于暗示此值不应该被修改,尽管可以被修改。如:
(defconst pi 3.14159 "A gross approximation of pi.")
let定义局部变量
(let ((variable value)
(variable value)
...)
body...)
例如:
(let ((zebra 'stripes)
(tiger 'fierce))
(message "One kind of animal has %s another is %s." zebra tiger))
布尔值
符号t表示true
符号nil表示false
算术
C/Java/JS Operator | Emacs Lisp | Example | Result |
+ | + | (+ 1 2 3 4 5) | 15 |
- | - | (- 6 2 3) | 1 |
* | * | (* 2 -1 4.2) | -8.4 |
/ | / | (/ 10 3) | 3 (use floats for float div) |
% | % | (% 10 2) | 0 |
<< | lsh | (lsh 1 5) | 32 |
>> | ash (negative amount) | (ash -32 -4) | -2 |
>>> | lsh (negative amount) | (lsh 32 -4) | 2 |
++ | incf (requires 'cl library) | (incf x 6) | x+6 |
-- | decf (ditto) | (decf x 5) | x-5 |
? : (ternary) | (if test-expr then-expr else-expr) | (if t 3 4) | 3 |
&& | and | (and t t t nil) | nil |
|| | or | (or nil nil nil t) | t |
! (logical-not) | not | (not 3) | nil |
~ (bit-not) | lognot | (lognot #b1001) | -10 |
^ (bit-xor) | logxor | (logxor 5 3) | 6 |
& (bit-and) | logand | (logand 1 3) | 1 |
| (bit-or) | logior | (logior 1 3) | 3 |
< | < | (< 5 3) | nil |
> | > | (> 5 3) | t |
<= | <= | (<= 3 3) | t |
>= | >= | (>= 5 3) | t |
. (field access) | see setf below | n/a | n/a |
[] (array access) | aref/aset | (aref [2 4 6] 1) | 4 |
如计算数学表达式 (0x15 * (8.2 + (7 << 3))) % 2在lisp中写为:
(% (* #x15 (+ 8.2 (lsh 7 3))) 2)
控制流
if/else
(if (>= 3 2)
(message "hello there"))
if/then/else:
(if (today-is-friday) ; test-expr
(message "yay, friday") ; then-expr
(message "boo, other day")) ; else-expr
在lisp中,判断函数一般用p结尾。
如果没有else语句而body又有多个表达式,则可用when
(when (> 5 1)
(message “5 is greater than 1!”)
(message “5 is greater than 1!!”)
(message “5 is greater than 1!!!”))
循环
while语句的格式为while test body-forms
例子:从1加到10
(setq x 10
total 0)
(while (plusp x) ; while x is positive
(incf total x) ; add x to total
(decf x)) ; subtract 1 from x
这里setq给多个变量赋值,后面依次填写参数。
也可使用loop宏,类似其它语言的for语句
(loop with result = '() ; one-time initialization
for i downfrom 10 ; count i down from 10
for j from 0 by 2 ; count j up from 0 by 2
while (< j 10) ; stop when j >= 10
do
(push (+ i j) result) ; fast-accumulate i+j
finally
return (nreverse result)) ; reverse and return result
for..in语句:
(loop for i in '(1 2 3 4 5 6)
collect (* i i)) ; yields (1 4 9 16 25 36)
Lisp使用catch/throw进行控制流的跳转。
break的实现:
Emacs Lisp | Javascript |
(setq x 0 total 0) | var x = total = 0; |
其中符号'break是可替换成其它值。
continue的实现
Emacs Lisp | Java |
(setq x 0 total 0) | var x = total = 0; |
函数
用defun定义函数
语法: (defun function-name arg-list [optional docstring] body)
(defun square (x)
"Return X squared."
(* x x))
(square 2)
对于没有参数的函数使用空列表:
(defun hello ()
"Print the string `hello' to the minibuffer."
(message "hello!"))
(hello)