典型的 lisp 缩进约定背后的规则是什么?

What are the rules behind the typical indenting conventions of lisp?

模组注意事项:请注意,这个问题根本不是品味问题。我要求提供有关我在 Spacemacs 的 elisp 默认缩进规则中遇到的缩进约定的具体信息。

为什么格式化程序将这段代码缩进成这样:

(defun lispy--maybe-safe-delete-region (beg end)
  "Delete the region from BEG to END.
If `lispy-safe-delete' is non-nil, exclude unmatched delimiters."
  (if lispy-safe-delete
      (let ((safe-regions (lispy--find-safe-regions beg end)))
        (dolist (safe-region safe-regions)
          (delete-region (car safe-region) (cdr safe-region)))
        (test))
    (delete-region beg end)
    (test)))

而不是这样:

(defun lispy--maybe-safe-delete-region (beg end)
  "Delete the region from BEG to END.
If `lispy-safe-delete' is non-nil, exclude unmatched delimiters."
  (if lispy-safe-delete
      (let ((safe-regions (lispy--find-safe-regions beg end)))
        (dolist (safe-region safe-regions)
          (delete-region (car safe-region) (cdr safe-region)))
        (test))
      (delete-region beg end)
      (test)))

如您所见,默认格式并未将 if sexp 的子项缩进同一级别。我不明白它的运作规则,因为 let sexp 的子级缩进在同一级别。

因为Emacs Lisp的IF运算符允许onethen形式和multiple else 形式。为了便于阅读,else 形式与 then 形式的缩进不同。

ELISP> (if (> 10 20)
           (print 'foo)
         (princ 'bar)
         (princ 'baz)
         nil)
barbaz
nil