阅读580 返回首页    go 阿里云 go 技术社区[云栖]


我也说说Emacs吧(7) - lisp基础

lisp基础

Lisp是仅次于Fortran的第二古老的着名计算机语言。
Lisp从一开始就与众不同的一点在于,它是基于S-表达式的语言。也就是说,代码和数据是用同一种方式表达出来的。
S-表达式,我们直观上理解,就是用括号括起来的一串列表。
比如:

(+ 1 1)

Lisp会对这个S-表达式进行求值。

S-表达式可以嵌套,比如可以这样写

(+ 1 (* 2 3))

在lisp中,默认的操作是对S-表达式求值。如果是个数字,就对数字直接求值。如果是字符串也是如此。如果是个表,则将第一个原子当成函数名,对其进行求值。

那么,如果我们只想将一个S-表达式当成数据,不要计算怎么办?我们可以使用quote符号来进行指定,比如:

(quote (+ 1 2))

结果就返回(+ 1 2)这个列表。
quote在lisp中实在是太常用了,所以我们可以用符号“’”来作为它的简称。

定义变量

大家都是写代码的老司机啦,我们就直接从定义变量开始说起。

定义变量可以使用set函数。

(set 'three (+ 1 2))

要注意,因为变量名是不求值的,所以要用quote或者'来阻止求值。将来用变量的值的时候就不用quote了。

定义变量的时候,符号是基本上不可能用求值的,所以'是基本上必须的。每次写太麻烦,于是专门有个setq特殊表,直接包含了对于第一个参数的不求值的quote行为。

定义局部变量:let特殊表

let可以定义局部变量。let定义的绑定只在函数内部起作用。

格式:

(let ((变量名 绑定值)(变量名 绑定值)) 语句)

例:

(let ((a 1)(b 2)) (+ a b))

a被赋值1,b被赋值2.最终表达式结果是3.

在let中,如果未指明绑定值,则自动绑定到nil上。

注释

emacs的注释以分号开头,分号之后全是注释。

表处理

car和cdr:取表头和其余部分

下面我们开始进入lisp不同于命令式语言的一个特色功能,表处理。

  • car函数:取一个表的第一个元素
  • cdr函数:取一个表的除了car取到部分的其它部分

例:

(car '(1 2 3))

将返回1.

(cdr '(1 2 3 4 5))

取得的结果是(2 3 4 5)

nthcdr函数:多次cdr

如果我们要从(1 2 3 4 5)这个表中取(3 4 5)这样的子表,一次cdr不够,需要做两次,像这样:

(cdr (cdr '(1 2 3 4 5)))

有个更简单的写法是使用nthcdr函数:

(nthcdr 2 '(1 2 3 4 5))

nthcdr的第一个参数,如果是0,则直接返回原表。如果是1,则退化成cdr。

cons函数:将car和cdr拼接起来

cons是car和cdr的逆运算。将两个表拼接成一个新表。
例:

(cons '1 '(2 3 4))

将得到(1 2 3 4).
请注意,cons会将第一个参数当成一个元素处理。
比如:

(cons '(1 2 3) '(4 5 6))

得到的结果不是(1 2 3 4 5 6)而是((1 2 3) 4 5 6)

求表长度:length函数

例:

(length '(1 2 4 5))

结果为4.

给表换car和cdr:setcar和setcdr函数

例:

(setq list1 '(1 2 3 4))
(setcar list1 5)

此时再通过C-h v去查list1的值,已经变为(5 2 3 4).

我们再将其后部也换掉:

(setcdr list1 '(6))

list1此时的值已经变成(5 6)

小结

  • setq特殊表:定义变量
  • let特殊表:定义函数内部的局部变量
  • car和cdr,nthcdr:取表头和其余部分
  • const: 构造新表
  • setcar, setcdr: 给表换头或换其余部分

最后更新:2017-06-13 17:31:40

  上一篇:go  STS(Eclipse)+Maven将war项目部署到远程的tomcat
  下一篇:go  Docker用以提高Linux内核安全性的三大热点技术