elisp学习笔记
参考: 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)