浏览 5477 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-06-25
这个笔记中,对Emacs Lisp中的一些名词:symbols、form、list等没有统一的叫法,对函数、form等也是混合着在使用,主要是为了能让自己更容易了解。 笔记正在增长中,笔记的原文是用emacs muse书写的,需要的朋友可以给我留言。 表处理 Lisp列表 数字,列表中的列表 列表里也可以包含数字:(+ 2 2)。 Lisp里的数据和程序都是相同的方式实现的,他们都是在括号中由单词、数字或者其它列表组成的用空白分隔的列表。因为程序看起来像数据,所以一个程序可以当作数据传递给另一个程序,这是lisp一强非常强大的功能。 Lisp原子 Lisp列表中的单词叫原子(意为原子在Lisp列表中不可再分割成更小的单位)。与原子不同,list可以分隔成更小的单位(car cdr & cons)。 空的列表:(),被称作空列表。与其它的数据类型不同,空列表被同时看作原子和列表。 与自然界的原子一样,Lisp中的原子这个名称来出现得太早(意指与自然界的原子一样,原子还可以再分割)。Lisp中部分原子,比如数组就可以进行分割。但是这种机制与列表的分隔是不同的。如果依据对列表的分隔方式来说,列表中原子就是不可分隔的了。 列表中的空白 额外的空白被用来提高代码的可读性。 '(this list looks like this) 与 '(this list looks like this) 是相同的。 列表排版 在Emacs Lisp mode下,有多种方法来对Lisp语句进行排版。比如,按<TAB>键将自动缩进当前光标所在行到正确的位置。M-C-\可以格式化当前所选区域中的代码。 运行一个程序 执行Lisp程序时,将执行下列三者之一: 1. 什么都不做,返回列表本身 2. 返回错误信息 3. 把列表中的第一个符号当作命令执行一些操作 放在列表前的单引号被称作引用(quote);当用它来处理列表时,它告诉Lisp不要对列表进行处理。但如果列表前没有单引号,则列表前的第一个元素是特殊的,它被当作命令被执行(Lisp中这些命令被称作函数)。列表(+ 2 2)显示也与加引号的列表的不同,Lisp知道需要用+来处理列表中的其它元素:把后面的数字相加。 生成错误信息 错误信息是由内置的GNU Emacs debugger生成的。进入debugger后,可以用按键q退出debugger。 符号名称和函数定义 Lisp中同一指令可以被绑定到多个名称。 另一方面,在同一时刻一个符号只允许绑定到一个函数定义上。 由于Emacs Lisp的庞大,它有一套按照不同函数功能分类的符号命名规则。如:所有处理Texinfo的函数都心textinfo-开头,而处理邮件的函数以rmail-开头。 Lisp解释器 Lisp的工作方式:首先,它查看列表前是否有单引号,如果有则解释器给出这个列表。如果没有引号,解释器检查列表中的第一个元素是否有对应的函数定义,如果找到则解释器调用函数定义的指令。否则,解释器将打印出错误信息。 复杂一点的内容 Lisp解释器可以对没有单引号且不被括号包围的符号。Lisp解释器将检测符号是否为一个变量。 一些函数不是普通的方法。被用来处理一些特殊的工作,比如定义一个函数。 Lisp求值时,将先对列表内部嵌入的列表进行求值,从内向外。 Lisp解释器工作时从左向右,从一个语句到另一个语句(从上至下)。 编译(Byte Compiling) Lisp解释器可以解释两种类型的代码:人可以读的代码和另一种被你为byte compiled code的代码。编译过的代码执行更快。 可以用byte-compile-file编译代码。被编译好的字节码文件扩展名为.elc。 求值 当Lisp解释器工作于一个语句上时,这个活动的过程被称为求值(evaluation)。求值完成后解释器将返回函数定义的执行结果,或者在函数出错时给出错误信息。 对内部列表求值 可以把光标停留在内部列表右括号的后面,按C-x C-e执行。 (+ 2 (+ 3 3)) 把光标放在括号后面,或者把光标放在代码下面的空行的行首,都可以得到8。如果用C-x C-e对一个数字求值将得到数字自身,这也是数字与符号的不同。 变量 Emacs Lisp中符号可以有一个值绑定到它或者一个函数定义绑定到它。两者不同在于,函数定义是指令的集合。值是可以修改的数字或者其它。符号的值可以是任意的Lisp表达式,比如符号、数字、列表、字符串等。有值的符号通常被称作变量。 符号可以同时有一个函数定义和值。两个是分开的。例: (defun test_f () "test2" (message "bbb")) (setq test_f "124") test_f -> 变量值"124" (test_f) -> 函数调用显示"bbb" fill-column一个变量的例子 变量fill-column,每个Emacs缓冲区,这个符号通常被设置成72或70,但也可能有不同的值。可以用C-x C-e对fill-column这个符号求值。 符号可以有值绑定到上面,我们可以绑定变量到值、数字、字符串、列表甚至是函数定义。 函数符号未定义时的错误信息 当我们对fill-column求值时将得到变量的值时并没有在符号外面添加括号。这是因为我们不打算将符号当作函数的名称。 如果fill-column是列表中的第一个元素或者唯一的元素,Lisp解释器将查找绑定到符号上的函数定义。但fill-column不是一个函数定义。当我们对 (fill-column) 求值时将产生错误信息: ---------- Buffer: *Backtrace* ---------- Debugger entered--Lisp error: (void-function fill-column) (fill-column) eval((fill-column)) eval-last-sexp-1(nil) eval-last-sexp(nil) call-interactively(eval-last-sexp) ---------- Buffer: *Backtrace* ---------- 函数fill-column未定义。 按q退出调试器。 符号没有值时的错误信息 例如对 (+ 2 2) 中的+号求值(光标停留在+的后面,按C-x C-e)时将产生错误信息: ---------- Buffer: *Backtrace* ---------- Debugger entered--Lisp error: (void-variable +) eval(+) eval-last-sexp-1(nil) eval-last-sexp(nil) call-interactively(eval-last-sexp) ---------- Buffer: *Backtrace* ---------- 这个错误信息与上节函数未定义时的不同。表示变量+未定义。 参数 参数类型 传递给函数的数据类型依赖于函数需要使用何种信息。比如+函数需要数字类型的参数。concat需要字符串类型的参数。substring是一个特殊一点的函数(称作原子粉碎机),它能把从原子类型中解析出一部分数据。 (substring "The quick brown fox jumped." 16 19) 变量值或者列表当作参数 例: (+ 2 fill-column) (concat "The " (number-to-string (+ 2 fill-column)) " red foxes.") 参数数量 一些函数可以带多个参数,例如:+、*。 (+) => 0 (*) => 1 (+ 3) => 3 (* 3) => 3 (+ 3 4 5) => 12 (* 3 4 5) => 60 使用错误类型的参数 当传递了错误的参数类型时Lisp解释器将产生错误信息。例如对 (+ 2 'hello) 求值的结果: ---------- Buffer: *Backtrace* ---------- Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p hello) +(2 hello) eval((+ 2 (quote hello))) eval-last-sexp-1(nil) eval-last-sexp(nil) call-interactively(eval-last-sexp) ---------- Buffer: *Backtrace* ---------- 错误信息的第一部分直截告诉我们参数类型错误(wrong-type-argument。第二个部分看起来有些迷惑number-or-marker-p,这部分告诉了我们+函数所需要的参数类型。 符号number-or-marker-p说明Lisp解释器检查提供给函数的信息(参数的值)是否是数字或marker(C-@或C-< SPC>设置的位置,mark可以被当作数字进行处理-mark在缓冲区中的字符位置)。Emacs Lisp中+可以将数字和作为数字的marker位置相加。 number-of-marker-p中的p是早期Lisp程序中的用法。p是'predicate'的简写。是早期Lisp研究者所使用的术语, predicate指明了函数用于决定一些属性是true还是false。因此p告诉我们number-or-marker-p是一个根据参数是否为数字或者marker而返回true或者false的函数。另一个以p结尾的Lisp符号包括zerop,这是一个检查参数值是否为0的函数,listp则是一个检测参数是否为一个列表(list)的函数。 最后,错误信息的其它部分将显示出符号hello。这是传递给+的参数值。 message函数 message函数显示信息到回显区。占位符%s表示字符串,%d为整数。例子: (message "This message appears in the echo area!") (message "The name of this buffer is: %s." (buffer-name)) (message "The value of fill-column is %d." fill-column) (message "There are %d %s in the office!" (- fill-column 14) "pink elephants") (message "He saw %d %s" (- fill-column 34) (concat "red " (substring "The quick brown foxes jumped." 16 21) " leaping.")) 设置变量值 有几种方法给变量赋值。set或setq函数,let函数。 使用set 要把符号flowers的值设置为列表'(rose violet daisy buttercup),可以执行下面的语句: (set 'flowers '(rose violet daisy buttercup)) 列表(rose violet daisy buttercup)将显示在回显区。这是set函数的返回值。另一方面符号flowers被绑定到列表;这样符号flower可以看作一个变量,它具有那个列表值。 在对set语句求值后,就可以对符号flowers求值,它将返回set设置的值。当对: flowers 求值时,回显区将显示(ros violet daisy buttercup)。 这时如果对'flowers求值,将在回显区看到符号自身flowers。 当使用set时,需要在两个参数前加单引号,除非你想对它们进行求值。如果没有加单引号,则解释器将先对参数进行求值,例如对flowers求值,如果flowers之前未赋过值,则将报错,如果对flowers的求值返回了值,则后面的变量值将赋给对flowers求值所返回的值上。这种情况非常少见。 (set 'flowers 'aaa) (set flowers "123") (message aaa) ->显示"123" 使用setq setq与set类似,但setq将自动给第一个参数前加单引号。另一方面,setq允许在一条语句中同时设置多个不同的变量值。例: (setq carnivores '(lion tiger leopard)) 与 (set 'carnivores '(lion tiger leopard)) 相同。 setq可以给多个变量赋值,例: (setq trees '(pine fir oak maple) herbivores '(gazelle antelope zebra)) 尽管我们一直在用赋值('assign'),但有另一种方式思考set和setq;即set和setq使一个符号指向(point)一个列表。 计数器 这是一个在计数器中使用setq的例子。 (setq counter 0) ; 初始化 (setq counter (+ counter 1)) ; 增加 counter 小结 * Lisp程序由表达式组成,表达式可以是列表或者原子。 * 列表由零个或者多个原子或内部列表组成,各元素由空白分隔,被括号包括。列表可以为空。 * 原子是多个字符符号,比如:forward-paragraph,单字符比如+,双引号间的字符串,数字。 * 对自身求值的数字。 * 双引号间的字符串也将对自身求值。 * 当对符号自身求值时,将返回它指向的值。 * 当对列表求值时,Lisp解释器查看列表中的第一个符号所绑定的函数定义。然后按定义的指令执行。 * 单引号,',告诉Lisp解释器应该把后面的表达式按原样返回,不对它进行求值。 * 参数是传递给函数的信息。函数是列表中的第一个元素,其它元素被求值并作为参数传递给函数。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |