勤劳,仍是懒惰?

前一篇《 第一声问候》讲述了如何用 Emacs Lisp 写一个能够在 Emacs 计算机里运行的 hello world 程序。

咱们已经经过一个极为简单的 hello-world 函数,向 Emacs 计算机发出了第一声问候。编程

这个 hello-world 函数的定义很是简单:segmentfault

(defun hello-world ()
  (interactive)
  (insert "hello, world"))

可是一旦弄懂了如何使用 Emacs Lisp 语言定义一个函数,以及 interactiveinsert 的用法,咱们就能够在不少时候从一个勤劳的人蜕变为一个懒惰的人。函数

此前,有一段时间,我常常用 POV-Ray [1] 渲染一些很简单的三维场景:我向 POV-Ray 提供场景文件,由 POV-Ray 使用光线追踪技术基于场景文件中的描述完成三维渲染。每份 POV-Ray 场景描述文件每每是如下面内容做为开始:code

#version 3.7;
#include "colors.inc"

global_settings {
  assumed_gamma 1.0
}

一开始我比较勤劳,会在每份场景文件中很认真地手动输入上述内容。如今就能够没必要如此,在 init.el 中像下面这样定义一个函数:orm

(defun povray-head ()
  (interactive)
  (insert
   "#version 3.7\n"
   "#include \"colors.inc\"\n\n"
   "global_settings {\n"
   "  assumed_gamma 1.0\n"
   "}\n"))

这样,每次当我新建了一份 POV-Ray 场景文件以后,只须要向 Emacs 发送 M-x povray-head <RET> 指令,场景文件中就会自动出现上述内容。get

看,并不须要多么高超的编程技术,只是将 hello-world 函数略微改动一下,就节省了许多重复性的劳动。从物理学的角度来看,在我编写许多 POV-Ray 场景描述文件时,这个 povray-head 函数可让我更省力。数学

因此,在我看来一个程序首先应该是一种有用的机械,它与杠杆、滑轮、斜面这些基本的省力装置不该该存在本质上的区别。所以,在写一个程序以前,须要明确,这个程序是否可让你或让其余使用这个程序的人更省力。不省力的程序,是不必去写的。string

最近为了写几篇 Emacs Lisp 编程方面的文章,我不得不在 Emacs 里编程。实际上我也常常须要使用 C 语言在 Emacs 的宿主系统中编程。我常常须要写一些像下面这样的代码:it

double *foo = malloc(n * sizeof(double));

若没学过 C 语言,就没必要在乎这行代码的含义,将它视为普通的文本便可。假若手写这行代码,我必须写两次 double。如今,我能够再在 init.el 中定义一个 c-malloc 函数,让我在写此类代码时可以省点力。io

如下是 c-malloc 的定义:

(defun c-malloc (name type n)
  (interactive
   (list (read-string "变量名称?")
     (read-string "类型?")
     (read-string "数量?")))
  (insert (format "%s *%s = malloc(%s * sizeof(%s));" type name n type)))

这个函数的定义,与 hello-world 以及 povray-head 不同,它是带有参数的函数。与后二者相比,它更符合咱们在数学中对函数创建的通常性认识,即 w = f(x, y, z) 或 f: (x, y, z) -> w。

暂时不考虑 c-malloc 的细节,先看它是如何工做的。

如今,假若 Emacs 从新加载了 init.el 文件,那么使用 M-x c-malloc <RET> 指令即可让 Emacs Lisp 解释器对 c-malloc 进行求值,可是 Emacs 在执行上述指令后,会在微缓冲区里问我三个问题。

第一个问题是:

变量名称?

我(在微缓冲区里)输入指令 foo <RET>,就回答了这个问题。紧接着,Emacs 会再问:

类型?

我输入指令 double <RET>,就回答了这个问题。最后,Emacs 会问:

数量?

我回答 n <RET>

注: <RET> 表示单击回车键。例如 n <RET>,表示输入 n 以后,单击回车键。

回答了这三个问题以后,Emacs 就会在缓冲区里显现:

double *foo = malloc(n * sizeof(double));

实际上,Emacs 接受个人答案以后,会将它们依序分别绑定到 c-malloc 的三个参数 nametypen 上,这就至关于造成了下面的表达式:

(c-malloc "foo" "double" "n")

接下来,Emacs Lisp 解释器对这个表达式进行求值,结果就是在缓冲区里插入

double *foo = malloc(n * sizeof(double));

像这些琐碎可是出现频率比较高的代码片断,花一点时间,用编程的方式来生成它们,不只省力,并且也避免了手工输入的错误。一个勤劳的人,应该用编程的方式让本身变懒,而不是让本身活成一段程序。

上文中出现的 Emacs Lisp 代码,看不懂没有关系,由于在下一篇就开始讲述 Emacs Lisp 的文本处理方面的编程知识。

下一篇原子与虚空

[1] http://povray.org/

相关文章
相关标签/搜索