【问题标题】:How to effectively read and write Lisp code?如何有效地读写 Lisp 代码?
【发布时间】:2014-07-18 13:46:30
【问题描述】:

我目前正在学习 Lisp,并且我认为我已经掌握了基础知识(我正在使用优秀的书 Land of Lisp,到目前为止,我已经阅读并完成了大约四分之一)。

我尝试根据我已经学到的知识创建自己的 Lisp 程序。不知何故,它起作用了。但这只是以某种方式。到目前为止,我主要使用 C 语法的语言进行开发,例如 C# 和 JavaScript(请注意,我非常清楚 JavaScript 不是基于 C 的语言)。

尽管如此,我习惯用 C 语法“思考”,当我用 C# 或 JavaScript 编写代码时,我可以用一种非常直接的方式写下来。相比之下,在编写 Lisp 代码时,我很难将所有这些括号括起来。

如果我有一个简单的语句,例如

(setf x (+ 2 3))

我总是发现自己试图从左到右阅读它,发现它不起作用,然后搜索最里面的一对括号,然后从内到外进行计算。对于这个简单的表达式,它的工作速度非常快。

但是,如果我有更复杂的代码(尽管它根本不复杂),比如使用let 的函数,那么(至少对我来说)找到最里面的一对括号会更难:

(defun foo ()
  (let ((x 23)
        (y 42))
  (+ x y)))

这里已经有点难以看出什么之后发生了什么,以及什么嵌套到什么。现在添加一些cond 的东西,也许再加上一些lambdas,我完全迷失了,发现自己数着括号数分钟(字面意思)。

写的时候也是这样,我迷失在括号的数量中,我什至还没有看到“复杂”的 Lisp 代码。

随着时间的推移,这会变得更好吗?也就是说,你习惯了吗?或者,有没有一些技巧可以让你更轻松地阅读和编写 Lisp 代码?更有经验的 Lisp 程序员如何做到这一点?有什么提示吗?

【问题讨论】:

  • 使用自动缩进代码的编辑器,例如 Emacs,使结构变得可见。例如。在你的最后一个例子中,(+ x y) 应该缩进两个空格,所以你可以看到它是 let 的主体。
  • 嗯,好的。这有助于写作,但阅读呢?例如,当我阅读 StackOverflow 上的代码时 ;-)?
  • 一旦代码正确缩进,你几乎可以忽略括号。随着时间的推移,你会习惯像 defunlet 这样的常见习语。
  • 刚刚为 Sublime 安装了lispindent,事实上,自动缩进真的很有帮助。惊人的 :-)。感谢您的提示!
  • 你是对的。 Javascript、c#、java、perl、c++ 和 c++ 都是 Algol 方言。由于您了解 Algol 的语法,因此很容易阅读。 Common lisp 和 Scheme 都是 Lisp 方言,如果你知道其中之一,就很容易阅读。

标签: lisp common-lisp readability code-readability


【解决方案1】:

您需要正确缩进。你的例子不是。

(defun foo ()
  (let ((x 23)
        (y 42))
  (+ x y)))

这里:

(defun foo ()
  (let ((x 23)
        (y 42))
    (+ x y)))

最后一个表达式需要右移。然后你可以看到它在 LET 里面。

Lisp 有一些结构模式。不是很多。一旦你学习和训练了这些,阅读 Lisp 就相对容易了。比学中文的人多得多。

一些模式:

(symbol ...)

符号给出锚

((a 10) (b 20))

绑定列表,例如LET

(with-foo (foo :option1 1 :option2 2)
  (body))

WITH-OPEN-FILE 这样的宏。

然后是复杂函数 arglist 本身。位置参数、可选参数、关键字参数。 &rest&aux

还有一些,但不会太多。一旦你学会了基本的宏和特殊的表单模式,代码阅读就会变得容易得多。

如何改善?阅读代码。火车。这并不难。有点像骑自行车。最初几天似乎很困难,然后它就自动完成了。

写作。

要编写代码,您需要一个可以缩进的编辑器。大多数只能缩进行,但不能格式化整个表达式。因此,您需要进行格式化。有一些基本规则。 Lisp 有一个漂亮的打印机,可以格式化。但这在编辑器中通常不可用,并且它不知道诸如 cmets 之类的东西。

当我编写一段 Lisp 代码时,我通常也会花一些时间来正确布局代码。

  • 行太长?
  • 悬空括号?
  • 结构正确吗?
  • 对齐方式?
  • 足够的视觉线索?
  • 命名?
  • 评论?
  • 文档?

【讨论】:

  • 非常有用的答案(到目前为止我读过的所有答案)!感谢您在 SO 上做了如此出色的工作 :-))
  • 现在十天过去了,我已经阅读和编写了一些 Lisp 代码,我不得不说,所有这些括号的危害都比我有的要小 很多一开始就预料到了。确实如此:如果缩进得当,几天后你就会停止计算(s 和)s,而是开始查看代码的实际结构。只是想补充一点,因为它可能对其他初学者有帮助:-)
  • @GoloRoden:采用:害怕括号,第一次训练,1(defun 2(foo)2 2(arg)2 2(sin 3(+ arg 2)3)2)1 , (defun foo (arg) (sin (+ arg 2))), defun foo arg sin(+ arg 2) , (defun foo (arg) (sin (+ arg 2))) ... 你会发现 PAREDIT 并在一段时间后您会发现括号的实际用途,...
【解决方案2】:

我也是 Lisp 的新手。但是,我发现它相对容易学习。

IMO 要记住的主要事情是 Lisp 是抽象语法树的直接表示。其他语言是面向文本的,并且它们的语法被建模为更接近人类语言,而 Lisp 是面向树的。因此,它需要一种完全不同的读写方式。如果你在数括号,那你就错了。

您应该学习将 lisp 代码作为树来阅读。使用正确的缩进器,它将自动表示为 s 表达式的第一个标记表示任何子树的根。因此,布局类似于树视图中的布局,例如Windows 资源管理器中的左侧。

也许这对我来说更容易,因为我编写了直接在 C/C++ 代码的 AST 上工作的分析软件。我记得当时从了解源代码到理解 AST 的步骤并不容易,我不断地犯错误,如果我考虑 AST,而不是一直考虑源代码,我本可以避免的错误。

出于这个原因,我推荐 ParEdit 用于 emacs 编写代码。 ParEdit 阻止您将 Lisp 代码编写为文本,而是允许(或强制,但您想调用它)您直接编写和转换 AST。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    • 2020-12-29
    • 2020-01-18
    • 2011-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多