我也说说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行为。
定义带文档的变量:defvar特殊表
setq特殊表几乎是lisp语言中最常用的特殊表,但是它有一个问题,变量没有文档。而在emacs中,函数和变量的文档是非常受到重视的。
对于代码中有重要作用的变量,在定义的时候,我们可以通过defvar特殊表来实现。
defvar特殊表不同于setq的是,它只针对未赋过初值的新变量有效,如果已经有值了,它就不起任何作用。所以我们在第一次定义变量的时候使用defvar特殊表吧,文档还是很重要的。
定义局部变量: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)
append函数:将两个表合成一个表
cons是将car和cdr合在一起,如果是想将(1 2 3)和(4 5 6)连接成(1 2 3 4 5 6),此时应该使用append函数:
(append '(1 2 3) '(4 5 6))
获取表中最后一个元素:last函数
car可以获取第一个元素,获取最后一个元素的话可以使用last函数。
构造一个新表: list函数
(list 1 2 3 4)
将构造出(1 2 3 4)表。
求表长度: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)
将表逆序排列:reverse函数
例:
(reverse '(1 2 3 4))
结果为:(4 3 2 1)
像命令语言一样顺序编程
Lisp基本上是一种函数式的语言。也就是说,如果在C语言中这样写的语句:
int a=func1(0);
int b=func2(a);
int c=func3(b);
换成lisp的写法是这样的:
(func3 (func2 (func1 0)));
我们来个小例子看看:
(defun func1 (x)
(+ x 1))
(defun func2 (x)
(* x 2))
(defun func3(x)
(* x x))
(func3 (func2 (func1 0)))
先执行的,要写在最里面。但是,学习命令式编程的同学们,习惯于先写最先执行的func1,倒过来写觉得思路转不过来。
Lisp善解人意地提供了progn特殊表,可以像C一样顺序执行。
我们可以这么写:
(progn
(setq a (func1 0))
(setq b (func2 a))
(setq c (func3 b)))
针对整个表的进行操作 - mapcar函数
Lisp毕竟是针对表进行处理的语言,如果像命令式的方式处理一个表未免有点low了。
假如我们想将一个表中的每个数字都求平方,我们先定义一个平方函数:
(defun sqr2 (x)
(* x x))
然后,我们就可以调用mapcar函数,对整个表都应用sqr2函数:
(mapcar 'sqr2 '(1 2 3 4))
针对这样只用一次的函数,我们可以使用lambda表达式来实现:
(mapcar (lambda (x) (* x x)) '(5 6 7 8))
lambda很有趣,既不是函数,也不是特殊表,而是一个宏。关于宏,我们后面再讲。
apply函数
最后介绍一下apply函数,它是可以将函数对表执行操作的函数。
我们看个例子:
(apply '+ '(5 6 7 8))
就相当于:
(+ 5 6 7 8)
小结
- setq特殊表:定义变量
- defvar特殊表:定义带有文档的变量,只能做第一次的初始化,有值就不能用了
- let特殊表:定义函数内部的局部变量
- car和cdr,nthcdr:取表头和其余部分
- last函数:取表尾
- cons: 构造新表
- length函数:求表长度
- append函数:将几个表合并为一个
- reverse函数:将表反序重排
- setcar, setcdr: 给表换头或换其余部分
- mapcar函数:针对每个元素分别进行操作
- apply函数:针对表执行操作
- lambda宏:定义匿名函数
- progn特殊表:顺序编程
我也说说Emacs吧(7) - lisp基础的更多相关文章
- Emacs学习心得之 基础配置
作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Emacs学习心得之 基础配置 1.前言2.基础配置 一.前言 本篇博文记录了Emacs的一 ...
- Emacs学习心得之 基础操作
作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Emacs学习心得之 基础操作 1.前言与学习计划2.Emacs基础操作 一. 前言与学习计 ...
- My Emacs For Common Lisp
My Emacs For Common Lisp My Emacs For Common Lisp
- emacs 下 common lisp 配置
安装 sbcl .emacs 加入 ;for lisp mode (add-to-list 'load-path "D:/kuaipan/.emacs.d/elpa/slime-201311 ...
- 我也说说Emacs吧(6) - Lisp速成
前面我们学习了基本操作,也走马观花地看了不少emacs lisp的代码.这一章我们做一个lisp的速成讲座. Lisp的含义是表处理语言.它的代码组成结构都是用括号组成的表来表示的.Lisp中的功能, ...
- 我的Emacs折腾经验谈(一) 一些给新人的建议
这几天都没有动力写mongodb的东西,我果然还是太懒了么~ 主要是没有一个系统的东西整理出来,加上我令人拙计的语言表达能力,这个坑只能慢慢再补了. 最近在折腾emacs这个东西,首先说我曾经算是个极 ...
- Emacs折腾经验谈
Emacs折腾经验谈 这几天都没有动力写mongodb的东西,我果然还是太懒了么~ 主要是没有一个系统的东西整理出来,加上我令人拙计的语言表达能力,这个坑只能慢慢再补了. 最近在折腾emacs这个东西 ...
- emacs最简单入门,只要10分钟
macs最简单入门,只要10分钟 windwiny @2013 无聊的时候又看到鼓吹emacs的文章,以前也有几次想尝试,结果都是玩不到10分钟就退出删除了. 这次硬着头皮,打开几篇文章都看完 ...
- 学习Emacs系列教程
emacs最简单入门,只要10分钟 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 3 ...
随机推荐
- 关于git pull时出现的问题及解决反思
前因 在前面由于已经git过一次,按照娄老师的要求,代码一个一个commit,所以删掉之前的git仓库(用la查看,使用rm -rf .git删除).但远程origin已经存在,所以执行git rem ...
- 20145303 《Java程序设计》第7周学习总结
20145303 <Java程序设计>第7周学习总结 教材学习内容总结 时间的度量 格林威治标准时间(GMT),现已不作为标准时间使用,即使标注为GMT(格林威治时间),实际上谈到的的是U ...
- 20145312 《Java程序设计》第五周学习总结
20145312 <Java程序设计>第五周学习总结 学习笔记 Chapter8 异常处理 8.1语法与继承架构 1.Java中的错误以对象方式呈现,只要捕捉包装错误的对象,就可以针对该错 ...
- 20145328 《Java程序设计》第9周学习总结
20145328 <Java程序设计>第9周学习总结 教材学习内容总结 第十六章 整合数据库 16.1JDBC 16.1.1JDBC简介 JDBC(Java DataBase Connec ...
- .NET数据库编程求索之路--1.引子
转载:[ 夏春涛 email: xchuntao@163.com blog: http://www.cnblogs.com/SummerRain ] 长期做.NET MIS系统开发,打交到最多还是数 ...
- Tomcat的配置,设置内存,获取用户IP
一.修改配置文件 tomcat配置文件路径/tomcat/bin/server.xml # shutdown指定终止Tomcat服务器运行时,发给Tomcat 服务器的shutdown监听端口的字符串 ...
- jquery 弹窗插件 layer 常见接口
源自:https://www.cnblogs.com/teamobaby/p/3556584.html 常见接口如下: 方法名 描述 $.layer({}) 核心接口,参数是一个对象,对象属性参见上述 ...
- 【cs231n】图像分类笔记
前言 首先声明,以下内容绝大部分转自知乎智能单元,他们将官方学习笔记进行了很专业的翻译,在此我会直接copy他们翻译的笔记,有些地方会用红字写自己的笔记,本文只是作为自己的学习笔记.本文内容官网链接: ...
- mysql悲观锁以及乐观锁总结和实践
悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中, 将数据处于锁定状态.悲观锁的实现,往往 ...
- nginx for windows 中虚拟主机路径设置问题
由于Windows版本的Nginx其实是在Cygwin环境下编译的,所以Nginx使用的是Cygwin的路径格式,所以在Nginx的配置文件nginx.conf中,路径既不能使用*nix的格式,也不能 ...