阅读《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 是基于表达式的,不是基于行的;对于多个顺序表达式,你可以把它们包在
progn或let里,这样就成为一个可编辑、可重新运行的单一形式。 - 一些实现或附加组件(带 readline 的 CLISP、rlwrap、linedit、CL 的 Jupyter 内核)提供了更像 IPython 的行历史,但大多数重点仍然是编辑器集成。
变量绑定、作用域,以及 let 与 let*
- 一个很长的子线程在讨论为什么 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 机器系统。