Skip to content

Commit 6d3eb8b

Browse files
committed
Change to markdown style code
1 parent f5e2a7d commit 6d3eb8b

15 files changed

+716
-564
lines changed

elisp/01-hello-world.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ title: 一个 Hello World 例子
55

66
自从 K&R 以来,hello world 程序历来都是程序语言教程的第一个例子。我也用一个 hello world 的例子来演示 emacs 里执行 elisp 的环境。下面就是这个语句:
77

8-
{% highlight cl %}
8+
``` cl
99
(message "hello world")
10-
{% endhighlight %}
10+
```
1111

1212
前面我没有说这个一个程序,这是因为,elisp 不好作为可执行方式来运行(当然也不是不可能),所有的 elisp 都是运行在 emacs 这个环境下。
1313

elisp/02-elisp-basic.md

Lines changed: 77 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,154 +8,173 @@ title: 基础知识
88
## 函数和变量 ##
99

1010
elisp 中定义一个函数是用这样的形式:
11-
{% highlight cl %}
11+
12+
``` cl
1213
(defun function-name (arguments-list)
1314
"document string"
1415
body)
15-
{% endhighlight %}
16+
```
1617

1718
比如:
18-
{% highlight cl %}
19+
20+
``` cl
1921
(defun hello-world (name)
2022
"Say hello to user whose name is NAME."
2123
(message "Hello, %s" name))
22-
{% endhighlight %}
24+
```
2325

2426
其中函数的文档字符串是可以省略的。但是建议为你的函数(除了最简单,不作为接口的)都加上文档字符串。这样将来别人使用你的扩展或者别人阅读你的代码或者自己进行维护都提供很大的方便。
2527

2628
在 emacs 里,当光标处于一个函数名上时,可以用 `C-h f` 查看这个函数的文档。比如前面这个函数,在 `*Help*` 缓冲区里的文档是:
2729

28-
hello-world is a Lisp function.
29-
(hello-world name)
30-
31-
Say hello to user whose name is name.
30+
```
31+
hello-world is a Lisp function.
32+
(hello-world name)
33+
34+
Say hello to user whose name is name.
35+
```
3236

3337
如果你的函数是在文件中定义的。这个文档里还会给出一个链接能跳到定义的地方。
3438

3539
要运行一个函数,最一般的方式是:
36-
{% highlight cl %}
40+
41+
``` cl
3742
(function-name arguments-list)
38-
{% endhighlight %}
43+
```
3944

4045
比如前面这个函数:
41-
{% highlight cl %}
46+
47+
``` cl
4248
(hello-world "Emacser") ; => "Hello, Emacser"
43-
{% endhighlight %}
49+
```
4450

4551
每个函数都有一个返回值。这个返回值一般是函数定义里的最后一个表达式的值。
4652

4753
elisp 里的变量使用无需象 C 语言那样需要声明,你可以用 setq 直接对一个变量赋值。
48-
{% highlight cl %}
54+
55+
``` cl
4956
(setq foo "I'm foo") ; => "I'm foo"
5057
(message foo) ; => "I'm foo"
51-
{% endhighlight %}
58+
```
5259

5360
和函数一样,你可以用 C-h v 查看一个变量的文档。比如当光标在 foo 上时用 `C-h v` 时,文档是这样的:
5461

55-
foo's value is "I'm foo"
56-
62+
```
63+
foo's value is "I'm foo"
5764
58-
Documentation:
59-
Not documented as a variable.
65+
Documentation:
66+
Not documented as a variable.
67+
```
6068

6169
有一个特殊表达式(special form)`defvar`,它可以声明一个变量,一般的形式是:
62-
{% highlight cl %}
70+
71+
``` cl
6372
(defvar variable-name value
6473
"document string")
65-
{% endhighlight %}
74+
```
6675

6776
它与 `setq` 所不同的是,如果变量在声明之前,这个变量已经有一个值的话,用 `defvar` 声明的变量值不会改变成声明的那个值。另一个区别是 `defvar` 可以为变量提供文档字符串,当变量是在文件中定义的话,`C-h v` 后能给出变量定义的位置。比如:
68-
{% highlight cl %}
77+
78+
``` cl
6979
(defvar foo "Did I have a value?"
7080
"A demo variable") ; => foo
7181
foo ; => "I'm foo"
7282
(defvar bar "I'm bar"
7383
"A demo variable named \"bar\"") ; => bar
7484
bar ; => "I'm bar"
75-
{% endhighlight %}
85+
```
7686

7787
`C-h v` 查看 foo 的文档,可以看到它已经变成:
7888

79-
foo's value is "I'm foo"
80-
89+
```
90+
foo's value is "I'm foo"
8191
82-
Documentation:
83-
A demo variable
92+
Documentation:
93+
A demo variable
94+
```
8495

8596
由于 elisp 中函数是全局的,变量也很容易成为全局变量(因为全局变量和局部变量的赋值都是使用 `setq` 函数),名字不互相冲突是很关键的。所以除了为你的函数和变量选择一个合适的前缀之外,用 `C-h f``C-h v` 查看一下函数名和变量名有没有已经被使用过是很关键的。
8697

8798
## 局部作用域的变量 ##
8899

89100
如果没有局部作用域的变量,都使用全局变量,函数会相当难写。elisp 里可以用 let 和 `let*` 进行局部变量的绑定。`let` 使用的形式是:
90-
{% highlight cl %}
101+
102+
``` cl
91103
(let (bindings)
92104
body)
93-
{% endhighlight %}
105+
```
94106

95107
bingdings 可以是 (var value) 这样对 var 赋初始值的形式,或者用 var 声明一个初始值为 `nil` 的变量。比如:
96-
{% highlight cl %}
108+
109+
``` cl
97110
(defun circle-area (radix)
98111
(let ((pi 3.1415926)
99112
area)
100113
(setq area (* pi radix radix))
101114
(message "直径为 %.2f 的圆面积是 %.2f" radix area)))
102115
(circle-area 3)
103-
{% endhighlight %}
116+
```
104117

105118
`C-h v` 查看 area 和 pi 应该没有这两个变量。
106119

107120
`let*``let` 的使用形式完全相同,唯一的区别是在 `let*` 声明中就能使用前面声明的变量,比如:
108-
{% highlight cl %}
121+
122+
``` cl
109123
(defun circle-area (radix)
110124
(let* ((pi 3.1415926)
111125
(area (* pi radix radix)))
112126
(message "直径为 %.2f 的圆面积是 %.2f" radix area)))
113-
{% endhighlight %}
127+
```
114128

115129
## lambda 表达式 ##
116130

117131
可能你久闻 lambda 表达式的大名了。其实依我的理解,lambda 表达式相当于其它语言中的匿名函数。比如 perl 里的匿名函数。它的形式和 `defun` 是完全一样的:
118132

119-
{% highlight cl %}
133+
``` cl
120134
(lambda (arguments-list)
121135
"documentation string"
122136
body)
123-
{% endhighlight %}
137+
```
124138

125139
调用 lambda 方法如下:
126-
{% highlight cl %}
140+
141+
``` cl
127142
(funcall (lambda (name)
128143
(message "Hello, %s!" name)) "Emacser")
129-
{% endhighlight %}
144+
```
130145

131146
你也可以把 lambda 表达式赋值给一个变量,然后用 `funcall` 调用:
132-
{% highlight cl %}
147+
148+
``` cl
133149
(setq foo (lambda (name)
134150
(message "Hello, %s!" name)))
135151
(funcall foo "Emacser") ; => "Hello, Emacser!"
136-
{% endhighlight %}
152+
```
137153

138154
lambda 表达式最常用的是作为参数传递给其它函数,比如 `mapc`
139155

140156
## 控制结构 ##
141157

142158
### 顺序执行 ###
143159
一般来说程序都是按表达式顺序依次执行的。这在 `defun` 等特殊环境中是自动进行的。但是一般情况下都不是这样的。比如你无法用 `eval-last-sexp` 同时执行两个表达式,在 if 表达式中的条件为真时执行的部分也只能运行一个表达式。这时就需要用 `progn` 这个特殊表达式。它的使用形式如下:
144-
{% highlight cl %}
160+
161+
``` cl
145162
(progn A B C ...)
146-
{% endhighlight %}
163+
```
147164

148165
它的作用就是让表达式 A, B, C 顺序执行。比如:
149-
{% highlight cl %}
166+
167+
``` cl
150168
(progn
151169
(setq foo 3)
152170
(message "Square of %d is %d" foo (* foo foo)))
153-
{% endhighlight %}
171+
```
154172

155173
### 条件判断 ####
156174

157175
elisp 有两个最基本的条件判断表达式 `if``cond`。使用形式分别如下:
158-
{% highlight cl %}
176+
177+
``` cl
159178
(if condition
160179
then
161180
else)
@@ -164,10 +183,11 @@ elisp 有两个最基本的条件判断表达式 `if` 和 `cond`。使用形式
164183
(case2 do-when-case2)
165184
...
166185
(t do-when-none-meet))
167-
{% endhighlight %}
186+
```
168187

169188
使用的例子如下:
170-
{% highlight cl %}
189+
190+
``` cl
171191
(defun my-max (a b)
172192
(if (> a b)
173193
a b))
@@ -179,34 +199,36 @@ elisp 有两个最基本的条件判断表达式 `if` 和 `cond`。使用形式
179199
(t (+ (fib (- n 1))
180200
(fib (- n 2))))))
181201
(fib 10) ; => 55
182-
{% endhighlight %}
202+
```
183203

184204
还有两个宏 `when``unless`,从它们的名字也就能知道它们是作什么用的。使用这两个宏的好处是使代码可读性提高,`when` 能省去 `if` 里的 `progn` 结构,`unless` 省去条件为真子句需要的的 `nil` 表达式。
185205

186206
### 循环 ###
187207

188208
循环使用的是 `while` 表达式。它的形式是:
189-
{% highlight cl %}
209+
210+
``` cl
190211
(while condition
191212
body)
192-
{% endhighlight %}
213+
```
193214

194215
比如:
195-
{% highlight cl %}
216+
217+
``` cl
196218
(defun factorial (n)
197219
(let ((res 1))
198220
(while (> n 1)
199221
(setq res (* res n)
200222
n (- n 1)))
201223
res))
202224
(factorial 10) ; => 3628800
203-
{% endhighlight %}
225+
```
204226

205227
## 逻辑运算 ##
206228

207229
条件的逻辑运算和其它语言都是很类似的,使用 `and``or``not``and``or` 也同样具有短路性质。很多人喜欢在表达式短时,用 `and` 代替 `when``or` 代替 `unless`。当然这时一般不关心它们的返回值,而是在于表达式其它子句的副作用。比如 `or` 经常用于设置函数的缺省值,而 `and` 常用于参数检查:
208230

209-
{% highlight cl %}
231+
``` cl
210232
(defun hello-world (&optional name)
211233
(or name (setq name "Emacser"))
212234
(message "Hello, %s" name)) ; => hello-world
@@ -218,10 +240,11 @@ elisp 有两个最基本的条件判断表达式 `if` 和 `cond`。使用形式
218240
(= (/ n (sqrt n)) (sqrt n))))
219241
(square-number-p -1) ; => nil
220242
(square-number-p 25) ; => t
221-
{% endhighlight %}
243+
```
222244

223245
## 函数列表 ##
224-
{% highlight cl %}
246+
247+
``` cl
225248
(defun NAME ARGLIST [DOCSTRING] BODY...)
226249
(defvar SYMBOL &optional INITVALUE DOCSTRING)
227250
(setq SYM VAL SYM VAL ...)
@@ -237,6 +260,6 @@ elisp 有两个最基本的条件判断表达式 `if` 和 `cond`。使用形式
237260
(or CONDITIONS ...)
238261
(and CONDITIONS ...)
239262
(not OBJECT)
240-
{% endhighlight %}
263+
```
241264

242265

0 commit comments

Comments
 (0)