mor*_*ode 2 lisp scheme code-formatting
考虑来自SICP的这个迭代因子过程.
(define (fact-iter product counter max-count)
(if (> counter max-count)
product
(fact-iter (* counter product)
(+ counter 1)
max-count)))
Run Code Online (Sandbox Code Playgroud)
在这里,我们看到:
为什么会这样?间距让我感到困惑.为什么它不能像java(在代码的每个内部添加四个空格)?我该如何格式化lisp代码?
Lisps的一个定义特性,包括Scheme,你编写的代码本质上是AST(抽象语法树).像Java这样的语言有很多语法,所以它们需要解析器正确消除歧义可能模糊的语法.中缀运营商就是一个典型的例子.考虑Java中的以下语句:
int x = 1 + y * 2;
Run Code Online (Sandbox Code Playgroud)
代码的文本表示肯定不会暗示任何树形结构,但实际上,这种说法有一个规范的解析是实际上是一个树.它看起来像这样:
=
/ \
int x +
/ \
1 *
/ \
y 2
Run Code Online (Sandbox Code Playgroud)
另一方面,等效的Scheme代码使得所有嵌套非常明确:
(define x (+ 1 (* y 2)))
Run Code Online (Sandbox Code Playgroud)
注意显式分组如何创建一个非常明确定义的表达式树.像大多数其他语言一样,不需要运算符优先级规则.这种简单性是一种有意的设计选择,因为当源代码表示非常简单时,编写转换它的宏非常容易.Lisps倾向于大量使用宏,因为与其他编程语言相比,操纵AST相对轻松,因为语法简单.
考虑到所有这些,缩进规则可能会变得更加明显:Lisp代码通常以这样的方式缩进,以便AST的结构立即可见.考虑fact-iter使用"更简单"缩进样式的示例函数的替代版本:
(define (fact-iter product counter max-count)
(if (> counter max-count)
product
(fact-iter (* counter product)
(+ counter 1)
max-count)))
Run Code Online (Sandbox Code Playgroud)
在这种特殊情况下,缩进并不是灾难性的,但fact-iter现在递归调用在视觉上解析起来要困难得多.Lisp/Scheme语法的一致性使得很难立即了解fact-iter使用三个参数调用的事实,因为第一个参数不再与后两个参数对齐.
这可以通过将所有参数放在单独的行上来解决:
(fact-iter
(* counter product)
(+ counter 1)
max-count)
Run Code Online (Sandbox Code Playgroud)
这个工作,实际上是可以接受的Lisp风格.尽管如此,它往往是对垂直空间的重大浪费,并且它仍然使AST更难以立即修复,因为压痕在视觉上显着不那么明显.
对于在Scheme中使用"更简单"缩进模型是灾难性的示例,请考虑以下两个等效表达式:
(string->number (if (string? x) x
(format "~a" x)))
(string->number (if (string? x) x
(format "~a" x)))
Run Code Online (Sandbox Code Playgroud)
第一个例子维护AST.很容易看出format调用是if表单的"else"情况,因为它嵌套在表单下面.第二个例子没有维护AST,乍看之下不清楚调用format是否嵌套在内部,if或者只是传递给第二个参数string->number.你可以看到Lisp的语法并没有真正说清楚.
方案缩进起初看起来有点时髦,但是一旦你习惯了它,它就会使代码更容易看到,而不必在脑子里耍弄括号.语法的一致性既是一种祝福又是一种诅咒:它使得编写宏变得微不足道,但它删除了一些使代码更容易理解的可视标记.拥有更多语义缩进系统有助于缓解这一缺陷.
Lisp有一些缩进代码的规则.使用最紧凑的版本.列表中元素的对齐很重要.还应考虑水平空间与可读性的最佳使用.
宏和特殊表单可以有自定义缩进规则.见下文.
函数有一些基于可用水平空间的缩进变体
例:
(append a b c) ; all arguments fit on a line
(append a ; arguments are aligned
b
c)
(append ; saving horizontal space, elements are aligned
a
b
c)
Run Code Online (Sandbox Code Playgroud)
像IF THEN ELSE这样的简单宏/运算符通常像函数一样对齐.
一个稍微复杂的情况是DEFINE:
(define (FUNCTION-NAME ARG0 ... ARGN) BODY-FORM-0 ... BODY-FORM-N)
Run Code Online (Sandbox Code Playgroud)
例子:
(define (foo a b) (print a) (append a b))
(define (foo a b)
(print a)
(append a b))
(define (foo a
b)
(print a)
(append a b))
(define (foo
a
b)
(print a)
(append a b))
Run Code Online (Sandbox Code Playgroud)
典型的Lisp漂亮打印机将根据可用的水平空间选择缩进变体.