【问题标题】:Lisp Code FormattingLisp 代码格式化
【发布时间】:2010-10-07 04:26:24
【问题描述】:

一位花时间在my other question 上评论 Clojure/LISP 语法的人指出,我没有以标准 LISP 方式编写示例代码。所以他好心重写了sn-p代码,这帮了大忙。但它在我的脑海中提出了另一个问题。为什么会这样:

(if (= a something)
  (if (= b otherthing)
    (foo)))

这是标准的 LISP 格式比这种形式更可取:

(if (= a something)
  (if (= b otherthing)
    (foo)
  )
)

由于我的 C++ 开发背景,这是我天真地格式化此代码的方式。我想知道后一种格式是否有任何好处,或者它只是一个根深蒂固的标准(如 QWERTY 键盘)。我并不是要争论——我很难理解为什么第一种形式更可取。第二种形式帮助我更容易地查看代码结构。

【问题讨论】:

  • 而不是
    (if (= a something) (if (= b otherthing) (foo))) 
    您可能需要考虑
     (when (and (= a something) (= b otherthing)) (foo)) 

标签: lisp clojure code-formatting


【解决方案1】:

额外行的右括号并不能真正帮助查看代码的结构,因为您可以从缩进级别获得相同的信息。然而,第二种形式占用了几乎两倍的行数,迫使您在阅读代码时更频繁地滚动。

如果您需要更仔细地检查嵌套括号,突出显示匹配括号的编辑器将为您提供帮助。当匹配的括号不太远时,这也会更容易。

如果表达式太长且太复杂而难以阅读,这也可能表明您应该将部分功能提取到单独的函数中。

【讨论】:

    【解决方案2】:

    Lisp 代码的缩进方式有点像 Python 中的重要空格,除了它当然是可选的。基本的经验法则是,如果列表中的项目不在同一行上,则将它们垂直放置在另一个列表中。

    (a (b (c (d e)
             (f g))
          (h i j))
       (k l m n))
    

    不用看括号,你可以看到(d e)(f g)c的参数,(c (d e) (f g))(h i j)b的参数,(b (c (d e) (f g)) (h i j))(k l m n)的参数是a 的参数。

    对于你的例子,它应该更正确地格式化如下:

    (if (= a something)
        (if (= b otherthing)
            (foo)))
    
        ^   ^
      notice how they line up
    

    现在缩进的级别变得有意义,您不再需要依靠平衡括号来获取该信息,并且由于将它们与结束语句放在同一行更紧凑,这就是 lispers 所做的。当然,Lisp 代码不需要以这种方式格式化,但它是人们使用并且可以依赖的相当标准的约定。

    【讨论】:

    • 关于空格和 Python 的要点。您可以将括号视为编辑器确定缩进的助手,否则忽略它们。顺便说一句,当你习惯了 Lisp 后,你就不会再“看到”它们了。
    • 我同意,就 Lisp 作为语言家族而言,您缩进 IF 形式的方式比 OP 的方式更传统和美观,但实际上,OP 的方式是(和不幸的是,在我看来)Clojure 约定。
    • 有趣的是,我刚刚检查了 Emacs,它像带有 IF 的 OP 一样缩进,但是使用随机名称它像我上面所做的那样缩进。也许 IF 有什么特别之处,但不一致很烦人。
    • IF 的不同缩进是因为 'foo' 是条件成立时发生的情况,因此不是 IF 的参数。
    【解决方案3】:

    简单的答案是你的方式不是 Lisp 的漂亮打印机做事的方式。拥有一个真正的格式对代码来说总是一件好事,而 pprint 宏为您提供了语言中内置的格式。

    当然,因为存在 pprint 宏,所以您不必严格遵循标准代码格式,因为人们可以通过 pprint 运行您的代码并获得他们习惯的内容。然而,由于其他人都使用 pprint,或者手动近似它,如果你不这样做,你将很难阅读代码,而且你没有一个简单的宏可以将他们的代码变成你喜欢的格式。

    【讨论】:

      【解决方案4】:

      您可以使用 Sreafctor 包重新格式化 Lisp 代码:Homepage

      一些演示:

      可用命令:

      • srefactor-lisp-format-buffer: 格式化整个缓冲区
      • srefactor-lisp-format-defun: 格式化当前defun光标所在
      • srefactor-lisp-format-sexp:格式化当前sexp光标所在的位置。
      • srefactor-lisp-one-line:将当前同级sexp变成一行;使用前缀参数,递归地将所有内部性别变成一行。

      格式化命令也可用于 Common Lisp 和 Scheme。

      如果有任何问题,请提交问题报告,我很乐意解决。

      【讨论】:

        【解决方案5】:

        当你有 10 个括号要关闭时,它会变得非常笨重。

        当我使用 Lisp 编程时,我在右括号之间留了一个空格,以便在同一行和其余的左括号之间留一个空格,以简化计数,如下所示:

        (如果(=某事) (如果(= b 其他) (富)))

        我想这些天不再需要了,因为编辑器更有帮助。

        【讨论】:

        • 我认为这是一个有用的约定;我得试试看。它对频繁编辑下的代码很有帮助,因为你可以看到线分割应该去哪里。
        • 这真是个糟糕的建议,真的。
        • 这有什么可怕的?
        • 在 1962 年的 LISP 1.5 程序员手册中有一个例子:kazimirmajorinc.blogspot.de/2012/03/…
        猜你喜欢
        • 2016-07-04
        • 1970-01-01
        • 1970-01-01
        • 2011-08-13
        • 2012-03-17
        • 2011-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多