- 论坛徽章:
- 2
|
回复 6# sanbiangongzi
一吐槽scheme就忘主题了。。。
具体到emacs lisp就很好说明了。el的执行是完全分为两步的。
代码文件中的: (cons 'a 1) , 如果该文件被加载, 就与(eval (read "(cons 'a 1)")) 等效。
首先是将代码文件中的字符流"(cons 'a 1)" —— 左括号, c, o, n ... 右括号 —— 读取为内存中的lisp object, (cons (quote a) 1) —— 一个三元素的列表,元素依次是cons(symbol), (quote a)(又一个列表,元素是quote符号和a符号), 1(number)。
然后就是求值,eval。不同类型的lisp object求值方式不同。
1. self evaluating, 比如number, string, vector。。。
对它们求值,返回这个lisp object本身。
2. symbol
el中的symbol有4个域, function cell, value cell, property list, 以及symbol name。对symbol求值就得到它的value cell。
3. list
对list求值就有点类似函数调用, 第1个元素的解释还比较复杂, 具体到这个问题其实只与后续元素的求值(即"参数")有关。
大多数时候,参数会被从左往右依次求值,并传递这个求值结果。
少部分special form对参数求值有特殊规定, macro对所有参数都不求值。
4. intern还有这一个关键概念前面忘记说了。
a, cons, b 等等都是interned symbol的read syntax。 读取,即(read "a")等,得到的是interned symbol。
不需要被它的名字吓到, lisp里有许多奇奇怪怪的名字。。。 它的目的就是保证代码中的所有a,读取后得到的都是同一个symbol object。
与之对应的是unintened symbol, 它们也都是symbol, 也有那4个域, 但可能就是不同的symbol object。
(read "(progn (setq b 1) b)") 得到一个list。 这个list中的两个b symbol是同一个symbol object。
如果对这个list求值, 即(eval (read "(progn (setq b 1) b)")), 首先是对progn求值。 progn 又会对它的参数 —— (setq b 1), b —— 依次求值,并返回最后一个参数的求值结果。
对(setq b 1)求值,就是将b这个symbol的value cell设置为1; 再对b求值,就是将同一个symbol的value cell取出, 就得到1了。
所以symbol 就可以用作变量 —— 一些地方用set, setq等设置symbol object的value cell, 另一些地方对同一个symbol object求值就取出value cell。
|
|