I'm a newbie playing around with Lisp (actually, Emacs Lisp). It's a lot of fun, except when I seem to run into the same syntax mistakes again and again.
For instance, here's something I've encountered several times. I have some cond
form, like
(cond
((foo bar)
(qux quux))
((or corge
(grault warg))
(fred)
(t
xyzzy)))
and the default clause, which returns xyzzy
, is never carried out, because it's actually nested inside the previous clause:
(cond
((foo bar)
(qux quux))
((or corge
(grault warg))
(fred))
(t
xyzzy))
It's difficult for me to see such errors when the difference in indentation is only one space. Does this get easier with time?
I also have problems when there's a large distance between the (mal-)indented line and the line it should be indented against. let
forms with a lot of complex bindings, for example, or an unless
form with a long conditional:
(defun test ()
(unless (foo bar
(qux quux)
(or corge
(grault warg)
(fred))))
xyzzy)
It turns out xyzzy
was never inside the unless
form at all:
(defun test ()
(unless (foo bar
(qux quux)
(or corge
(grault warg)
(fred)))
xyzzy))
I auto-indent habitually and use parenthesis highlighting to avoid counting parentheses. For the most part it works like a breeze, but occasionally, I discover my syntax mistakes only by debugging. What can I do?
First of all, turn on the builtin paren match highlighting (show-paren-mode
) if not already did so. It always gives you an idea what indentation level you are in.
There are also some more sophisticated packages. For example, see TJ's answer on mic-paren
. Or though I didn't find it suitable for me, but there is Schumacher's highlight-parentheses mode that highlights every expression block with different colors. Even Edward O'Connor has a mode that highlights the current sexp.
Use paredit-mode
which helps you writing sexps. You can easily navigate between sexps and re-structure the code. In addition, it ensures the parenthesis always balanced. When I first tried it, it was very annoying for me how Paredit constrains the way of coding, but since then I'm used to work with it, I'm a lot more productive and never get confused with opening and closing parenthesis.
Use Emacs Starter Kit, which, by default, enables a lot of useful helpers for coding in Elisp like re-indent on newline.
emacs-lisp-mode
has several useful extensions. For instance, I always use eldoc-mode
that displays currently typing function's argument list or variable's docstring in the echo area. It also helps you easily recognize if you are in the wrong block.
I've just nearly forgotten to mention Edebug which—as a last chance—always helps you figuring out what's going on in your code.
Here are three concrete things you can do to help with spotting Lisp syntax problems. In time, it'll become second nature. But until then:
Parenthesis matching is the easiest way to check the grouping. My favorite package is mic-paren. And I like this particular configuration:
(setq paren-dont-touch-blink t)
(require 'mic-paren)
(paren-activate)
(setq paren-match-face 'highlight)
(setq paren-sexp-mode t)
That causes the sexp (matching parenthesis) to be highlighted when the point is at the beginning/end of the sexp. If the parenthesis don't match, the highlight color is different - and brighter. When the matching parenthesis is off-screen, it shows you what that end looks like in the minibuffer (and tells you how many lines away it is).
For a slightly more involved method, you can run the Elisp compiler with M-x compile-defun
. For example, when I compiled this simple example:
(defun mytestfun ()
(let ((cur (current-buffer)))
)
(set-buffer cur))
I got a buffer named *Compile-Log*
which said:
Warning: reference to free variable `cur'
Which clued me into the fact that I was using cur
outside of the let
statement that defined it.
If you want the indentation to be more prominent, you can customize the variable listp-body-indent
:
(setq lisp-body-indent 4) ;# default is 2
You can also customize how various constructs are indented, but I don't advise that because it'll be non-standard and might lead to confusion when looking at most Lisp code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With