阅读《A Programmer's Guide to Common Lisp》

Common Lisp 爱好者讨论如何在这门语言中高效学习和工作,对比了按行输入的 REPL 与 IPython 之类工具,并推荐使用 Emacs+SLIME、Vim+VLIME,甚至基于 Jupyter 的交互式开发环境。交流的大部分内容集中在 Lisp 的显式作用域与绑定构造(如 `let` 与 `let*`)上;有人认为它们有助于推理和元编程,也有人把它们视为妨碍采用的历史包袱。除了工具和语言设计,参与者还赞赏较早的 Lisp 和编程书籍,以及像 Medley 这样的经典 Lisp 机器环境,认为它们是探索符号计算的独特而自洽的方式。

Common Lisp REPL 和迭代式工作流

  • 一些评论者觉得 CL REPL 比 IPython 更笨拙,尤其是在处理多行片段和历史编辑时。
  • 有经验的用户表示,“正确”的方式不是在裸露的终端 REPL 里直接输入,而是使用与编辑器集成的 REPL(“listener”)。
  • 在 Emacs+SLIME 或 Vim+Slimv/Vlime 中,你在缓冲区里编写代码,并通过键绑定把表达式、区域或形式发送到 REPL。这提供了多行求值和方便的重新求值,而不依赖按行历史。
  • CL REPL 是基于表达式的,不是基于行的;对于多个顺序表达式,你可以把它们包在 prognlet 里,这样就成为一个可编辑、可重新运行的单一形式。
  • 一些实现或附加组件(带 readline 的 CLISP、rlwrap、linedit、CL 的 Jupyter 内核)提供了更像 IPython 的行历史,但大多数重点仍然是编辑器集成。

变量绑定、作用域,以及 letlet*

  • 一个很长的子线程在讨论为什么 CL 使用 let/let* 这类形式,而不是像 var x = y 这种“在任何地方声明变量”的语法。
  • 支持者认为显式作用域是一种特性:绑定是局部的,更容易推理,也更适合宏和元编程。let 类似 lambda 参数绑定;let* 表达顺序依赖。
  • 批评者觉得这种区别令人困惑,而且相较于 C 风格语言或允许在块内使用 define 的 Scheme 语言并不符合习惯,认为它强迫更多嵌套并损害可读性。
  • 还有人指出,许多非 C 语言历史上也要求在作用域顶部声明变量;“现在大多数语言都这么做”的说法也受到了质疑。
  • 文中提到各种宏(nest、将 var 改写为嵌套 let 的类块宏、TXR Lisp 结构),作为在不改变核心语言的情况下获得替代语法风格的方法。
  • 历史背景:let 是后来作为 lambda 的语法糖出现的;let* 更晚出现,而命名很大程度上是历史遗留,而不是全新的设计。

书籍、文档风格,以及学习 Lisp

  • 评论者称赞较早的技术书籍(包括 Lisp 和 AWK 相关书)自成体系、按线性方式组织,而且不假定始终要上网查阅。
  • 许多人喜欢阅读过时的手册和语言书,因为它们具有视角、风格以及“时间截面”的感觉。
  • 文中提到的具体 Lisp 学习路径包括适合初学者的入门材料和面向 AI 的 Common Lisp 书籍。
  • 有人将较早、稳定的平台(DOS、早期 Windows、经典 Lisp 系统)与现代、仅限网络且碎片化的文档进行对比,认为后者更难线性浏览。

Lisp Machines、Medley,以及相关系统

  • 有些人喜欢 Medley/Interlisp 作为一种自包含的、类似 Lisp 机器风格的环境,不过也有人更偏好现代 CL 实现加 Emacs,或商业 IDE。
  • Mathematica 被提到具有某种 Lisp 风格的感觉,以及庞大的内置库,但它的目标和实现都不同于 Lisp 机器系统。