我是一个玩弄Lisp的新手(实际上是Emacs Lisp).这很有趣,除非我似乎一次又一次遇到相同的语法错误.
例如,这是我多次遇到过的事情.我有一些cond
形式,比如
(cond ((foo bar) (qux quux)) ((or corge (grault warg)) (fred) (t xyzzy)))
并且xyzzy
永远不会执行返回的默认子句,因为它实际上嵌套在前一个子句中:
(cond ((foo bar) (qux quux)) ((or corge (grault warg)) (fred)) (t xyzzy))
当缩进的差异只有一个空格时,我很难看到这样的错误.这会变得更容易吗?
当(错误的)缩进线与应该缩进的线之间有很大的距离时,我也会遇到问题.let
例如,具有大量复杂绑定的unless
表单,或具有长条件的表单:
(defun test () (unless (foo bar (qux quux) (or corge (grault warg) (fred)))) xyzzy)
事实证明xyzzy
,从来没有在unless
形式内:
(defun test () (unless (foo bar (qux quux) (or corge (grault warg) (fred))) xyzzy))
我习惯性地自动缩进并使用括号突出显示以避免计算括号.在大多数情况下,它像微风一样,但偶尔,我只通过调试发现我的语法错误.我能做什么?
首先,打开内置的paren match highlighting(show-paren-mode
),如果还没有这样做的话.它总能让您了解缩进级别.
还有一些更复杂的包.例如,请参阅TJ的答案mic-paren
.或者虽然我没有发现它适合我,但有舒马赫的高亮括号模式突出显示每个不同颜色的表达块.甚至爱德华奥康纳也有一种突出当前性别的模式.
使用paredit-mode
它可以帮助你写性别.您可以轻松地在sexps之间导航并重新构建代码.此外,它确保括号始终平衡.当我第一次尝试时,对我来说非常讨厌Paredit如何限制编码方式,但从那时起我就习惯了它,我的工作效率更高,并且永远不会对开括号和右括号感到困惑.
使用Emacs Starter Kit,默认情况下,它允许很多有用的帮助程序在Elisp中进行编码,就像在换行符上重新缩进一样.
emacs-lisp-mode
有几个有用的扩展.例如,我总是使用eldoc-mode
当前在echo区域中键入函数的参数列表或变量的docstring的显示.它还可以帮助您轻松识别您是否在错误的区域.
我几乎忘记提到Edebug - 作为最后一次机会 - 总能帮助您弄清楚代码中发生了什么.
以下是帮助发现Lisp语法问题的三个具体方法.随着时间的推移,它将成为第二天性.但在那之前:
括号匹配是检查分组的最简单方法.我最喜欢的包是mic-paren.我喜欢这个特殊的配置:
(setq paren-dont-touch-blink t) (require 'mic-paren) (paren-activate) (setq paren-match-face 'highlight) (setq paren-sexp-mode t)
当点位于性别的开始/结束时,这会导致性别(匹配的括号)突出显示.如果括号不匹配,则突出显示颜色不同 - 并且更亮.当匹配的括号在屏幕外时,它会显示迷你缓冲区中的那个结尾(并告诉你它有多少行).
对于稍微更复杂的方法,您可以运行Elisp编译器M-x compile-defun
.例如,当我编译这个简单的例子时:
(defun mytestfun () (let ((cur (current-buffer))) ) (set-buffer cur))
我有一个名为的缓冲区*Compile-Log*
,其中说:
警告:引用自由变量`cur'
这让我想到了我在定义它cur
的let
语句之外使用的事实.
如果希望缩进更加突出,可以自定义变量listp-body-indent
:
(setq lisp-body-indent 4) ;# default is 2
您还可以自定义各种构造的缩进方式,但我不建议这样做,因为它是非标准的,并且在查看大多数Lisp代码时可能会导致混淆.