20070610

[合集] 程序员的elisp入门 (1)(转寄)

发信人: nichloas (nil), 信区: Emacs
标 题: [合集] 程序员的elisp入门 (1)
发信站: BBS 水木清华站 (Wed Mar 10 19:33:51 2004), 站内

☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Wed Nov 19 23:41:28 2003) 提到:

偶来写一点东东,介绍一下一个已经会写程序的人(比如我自己),怎么理解
elisp这个东西。

想来想去,if,cond这种东西就不介绍了,偶相信那些在书里面花费若干
版面介绍if,cond,loop,when,unless是什么意思,该怎么用的,都是
骗人钱财。

现在准备写的,包括怎么用emacs自己带的帮助系统,和elisp语言本身。
昨天晚上关于cons的是第一片。

* 操作入门

启动emacs之后,这个被称为*scratch*的buffer,可以拿来当作实验室。
只要在想要求值的符号之后输入C-x C-e,求值的结果就会显示在屏幕下端
的mini buffer里面。如果输入C-u C-x C-e的话,求值的结果会直接贴到
point当前在的位置。

无论什么模式下,C-h f能够显示一个函数的doc文档,C-h v能够显示一
个变量的doc文档。这对于写程序非常有帮助,所以自己写的函数,最好也
能够把doc文档写上,将来自己或者别人都可能用的上。

* 基本概念

** elisp只有一种数据类型,就是symbol。

所有能看的字符串,都是symbol。所有symbol都可以求值。 所有的
symbol都是平等的,不过其中有一些更平等。表示数字的symbol,例如0,
12.3, 234。求值得到的还是这个数字本身。表示字符串的symbol,例如
"hello","world",求值得到的还是字符串本身。表示keyword的symbol,
例如:foo,:bar,求值得到的还是keyword本身。更特别一点的,t求值返
回的是t,nil求值返回的是nil。最特别的是,()求值返回nil,因为()和
nil根本就是一回事情。

一个symbol可以同时指代变量和函数,就是说一个foo,即是变量,又是
函数,在lisp里面是合法的。

** 所有对symbol进行的操作,被称为函数。

使用函数的方法是(function var1 var2 var3)。这个例子很显然的告诉
我们,括号不能出现在symbol里面,空格也不可以。但是例如*,/这样奇怪
的符号是可以的。

一个函数被调用的过程,被称为对这对括号内部求值。注意到之前对
symbol也叫求值,这实际上暗示var1,var2,var3不一定是一个symbol,
也有可能是其他的函数调用。如果整个程序就是这样的函数一层一层嵌套
得到的时候,我们可以粗略的把它称为函数式编程语言。

(function var1 var2 var3)这样的一个函数,具体求值的过程,对于
elisp来说,它先求function的值,然后求每一个var的值,最后将对var求
值得到的结果,做为参数传递给function求值的结果。之所以强调先求,
然后求;而不是说从左到右依此求,是因为对于括号中的第一个symbol是
特别照顾的。

我们至少可以总结出两点。我们对一个symbol求值时,到底是希望得到
它代表的函数,还是希望得到它代表的变量,这完全取决于这个symbol所
处的位置。第二,elisp中,函数和变量并不是完全平等的,你不能再象
scheme中那样了。即使你(setq func (lambda (...))),也无法直接
把它做为一个function来做,因为setq就注定了func只能被当作一个变量
来处理,而lisp只会试图去找func对应的函数。

☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Wed Nov 19 23:42:38 2003) 提到:

附注

偶不是emacs的manual,这个全凭理解写的东西,很可能是错的,有错的话就
拍砖吧。 ;)

☆─────────────────────────────────────☆
ilovecpp (cpp) 于 (Wed Nov 19 23:56:52 2003) 提到:

我在*scratch*里都是直接C-j的

☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:01:15 2003) 提到:


☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:14:11 2003) 提到:

我好象直接把value叫做变量了,可能比较模糊。改一下好了。

elisp会根据位置决定要去求function,还是去求value;而不是
反过来,先求出一个东西,然后决定它是function,还是value。

比如
(setq hhuu (lambda (a b) (message "crying...")))
(hhuu 1 2)
会触发void-function错误,就是elisp试图求出hhuu所代表的
function,但是找不到。

我是这样理解的。

☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:17:54 2003) 提到:

这样的时候要求使用 funcall吧
(setq f 'list)
=> list
(funcall f 'x 'y 'z)
=> (x y z)
elisp里面的例子。
(defun f (x) (* x x))
(f 2)是正确的 (funcall f 2)也是正确的。
对于函数指针来说 只能用 funcall


☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:25:44 2003) 提到:

试验里一下 elisp 里面这种绑定是这个意思。

(defun f (x) (* x x))
这是 f的函数值 为这个函数, f的symbal值为这个函数的指针。
所以 (f 2) 和 (funcall f 2) 都是正确的。
然后执行 (setq f 1)
这个时候 f的 symbal值被改掉了。
(f 2)还是成功,但是 (funcall f 2)失败了。

☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:27:09 2003) 提到:

funcall或者apply都可以,apply可能更常用一点。

elisp里面给的例子,我感觉是因为defun比较特殊。
defun是个special form,感觉上它同时占了function
和value的名字空间。

比如象(funcall cons 1 2)这样就是错误的,
而(funcall 'cons 1 2)就是正确的。

或者一个比较明显的例子。
;; 定义func的value
(setq func (lambda (a b) (* a b)))
;; 定义func的function
(defun func (a b)
""
(+ a b))
;;调用
(funcall func 1 2) ;; -> 2
(funcall 'func 1 2) ;; -> 3
可见funcall对于symbol做了特殊处理,而
func在第二个位置上被求值,获得的依然是他的value。

☆─────────────────────────────────────☆
RoachCock (chen3feng) 于 (Thu Nov 20 00:28:17 2003) 提到:

解释一下setq, defun, require,还有半个单引号"'"吧

☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:29:42 2003) 提到:

明天吧......

☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:32:41 2003) 提到:

setq 可以理解为赋值
require 可以理解为 java 里面的 import
defun 就是定义函数
' 用来停止求职,
一般来说 (f x y z)
lisp会先对 f x y z都求职然后再调用函数 f
(f 'x 'y 'z)表示 x y z 都是最后的值了,不需要进行求职了。


☆─────────────────────────────────────☆
RoachCock (chen3feng) 于 (Thu Nov 20 00:35:12 2003) 提到:

前三个可否理解为预定义函数?

☆─────────────────────────────────────☆
ilovecpp (cpp) 于 (Thu Nov 20 00:36:09 2003) 提到:

defun不是,不会对它后面的东西求值,叫special form

☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:38:23 2003) 提到:

除了require以外都是special form。
function都严格遵循求值顺序,special form可以当成宏来理解,
就没有什么求值的关系了。

☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:39:05 2003) 提到:

setq defun require 中 setq应该是一个macro
defun算是 special form
require 好像是个函数


☆─────────────────────────────────────☆
RoachCock (chen3feng) 于 (Thu Nov 20 00:39:05 2003) 提到:

(global-set-key [(control shift tab)] 'tabbar-backward)
(global-set-key [(control tab)] 'tabbar-forward)

方括号如何理解?

☆─────────────────────────────────────☆
RoachCock (chen3feng) 于 (Thu Nov 20 00:40:47 2003) 提到:

如何定义宏? setq适于定义的吗?不是的话在那里定义的?

☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:42:24 2003) 提到:

array吧

☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:42:47 2003) 提到:

defmarco可以定义宏.
setq在lisp里面一般都是系统预定的macro
不过setq应该可以用 defmacro定义出来。


☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:43:11 2003) 提到:

☆─────────────────────────────────────☆
RoachCock (chen3feng) 于 (Thu Nov 20 00:44:24 2003) 提到:

defmacro适于定义的宏还是函数或者special form?


☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:44:44 2003) 提到:

vector
修正一下,我名词记得不好。 -_-!

☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:45:40 2003) 提到:

special form,最后一般都能推到 special form


☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:46:44 2003) 提到:

不是故意的

☆─────────────────────────────────────☆
RoachCock (chen3feng) 于 (Thu Nov 20 00:47:30 2003) 提到:

special form是elisp最根本的东西了? special form有多少个?

☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:48:25 2003) 提到:

elisp 里面既有array又有vector vector 是array一种


☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:51:30 2003) 提到:

理论上elisp可以推导到只有lambda

special form大致上就是说,为了方便使用,特此例外。
所以凡是例外的一般都是special form。
有的东西叫special form其实没什么道理,比如setq。

☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:52:55 2003) 提到:

我也不理解为什么elisp的setq不是宏,好像CL里面setq就是set的一个包装

elisp这个还是比较特殊的。


☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:53:03 2003) 提到:

了解了

本来概念里面只有list,array, string三种序列的
刚才翻了一下手册,array包含string,还包含char vector,和
bool vector。 ft,真的折腾,那么多。

☆─────────────────────────────────────☆
ggp (宝宝糕) 于 (Thu Nov 20 00:54:35 2003) 提到:

发现CL里面setq也是special form :(真没有注意。


☆─────────────────────────────────────☆
hhuu (apply->eval->apply) 于 (Thu Nov 20 00:56:04 2003) 提到:

cl里面的setq也叫special form。 ilisp挺好用的,现在查cl的帮助特别快。 ;)

☆─────────────────────────────────────☆
MountainKing (山丘之王) 于 (Thu Nov 20 00:57:45 2003) 提到:

什么意思呀?
special form都可以用lambda表示?