← 返回信息流
AI 资讯Hacker News·3 小时前

Lisp学习之路:为何选择Lisp

原标题:A Road to Lisp: Why Lisp

速览

本文介绍了Lisp语言的历史与现代应用,分析了其独特语法和强大功能,适合编程爱好者深入了解。Lisp在人工智能早期发展中扮演重要角色,至今仍具有教学意义。

AI 深度解读

背景

Lisp 是一门拥有数十年历史的编程语言,以其独特的全括号语法和强大的元编程能力而闻名。然而,对于大多数首次接触 Lisp 的程序员来说,第一反应往往是:“这到底是什么鬼?”这种困惑源于其非传统的语法——大量括号、奇怪的缩进、以及像 format 的第一个参数竟然是标准输出流这样的设计。本文作者在 Hacker News 上分享了自己学习 Lisp 的心路历程,重点探讨了为什么这门看似古怪的语言值得学习,以及它如何从根本上改变程序员的思维方式。

核心内容

作者坦言,学习 Lisp 是一条陡峭的学习曲线。在习惯了密密麻麻的括号之后,还需要掌握包(package)与符号(symbol)、项目创建与库导入、REPL 的使用、条件(conditions)与重启(restarts)等机制。最重要的是,在构建算法时必须切换到一个全新的思维模式。

Paul Graham 曾提出“Blub 悖论”(Blub paradox)来解释为何只用过“更弱”语言的程序员难以理解 Lisp 的强大:他们缺乏察觉自身语言缺陷所需的概念,自然也就无法理解 Lisp 的优势。Louis Armstrong 对爵士乐的评价也类似:“如果你非得问什么是爵士乐,那你永远不会懂。”作者指出,学习 Lisp 不仅是为了掌握一门语言,更是为了获得看待编程的全新视角——即使最终不使用 Lisp,你也会对编程语言的能力有更深刻的认识。

Lisp 会让你成为更好的程序员,因为它改变了你用代码思考问题的方式。具体来说,它将教会你一种其他编程语言无法提供的方法:你可以对 Lisp 本身进行编程,从而将语言调整为你所解决的问题服务,即“把语言向你的问题生长”,然后在该语言中编写程序。

可扩展性(Extensibility)

Lisp 可以在自身内部被扩展。专家(称为 Lispers)常称之为“可编程的编程语言”。你不仅能为程序写代码,还可以编写扩展 Lisp 本身的代码。这得益于宏运算符(macro)。如果你曾在 C、Rust 或 Swift 中使用过宏,不要以为 Lisp 的宏与之相同——那些语言的宏主要用于消除样板代码或生成重复代码。而 Lisp 的宏可以创建成为语言一部分的新构造。

为了展示宏的能力,作者以 while 为例:Common Lisp 本身没有 while 运算符,但程序员可以编写一个宏将它添加到语言中。该宏接受一个条件(condition)和一个主体(body),利用内置的 loop 宏实现循环。通过 defmacro 定义后,就可以像 C 语言一样使用 (while condition body) 的语法。相比之下,如果试图用普通函数(defun)实现同样的功能,由于参数会被立即求值,会导致错误:例如 (< x 3) 会求值为 tbody 中的表达式也会被立即求值并返回一个数值,而不是一段待执行的代码。宏则因为不对参数进行提前求值,将条件与主体视为纯数据,从而能够正确控制执行流程。

代码即数据(Code as Data)

Lisp 程序由符号表达式(s-expression)组成。符号表达式要么是原子(atom,如数字、字符串、符号),要么是列表(list,包含原子或其他列表)。Lisp 的含义就是“列表处理”(LISt Processing)。由于列表既被用作主数据结构,又被用来书写代码,Lisp 展现出一种重要的特性:同像性(homoiconicity)——代码和数据都用列表表示。

例如,(+ 1 2) 是一个列表,它被求值为 3(代码)。而在前面加上引号 '(+ 1 2) 则将其视为数据,求值结果就是该列表本身而不被求值。代码与数据的这种微妙区别正是宏得以实现的基础:我们可以像操作数据一样操作代码,通过转换源代码来编写“写程序的程序”。这种能力是其他语言多年来试图模仿的。

通过扩展语言,你可以为特定问题领域创建更具表达力的新构造,使代码更加简洁。重复的样板代码可以用自定义宏替换,从而缩短代码、节省时间;可以创建新的控制结构来管理资源访问和表达式求值;宏还能生成代码、提升性能,最重要的是能创建更易理解的新型语法抽象。

关键要点

  • Lisp 的学习曲线陡峭:需要适应全括号语法、REPL 工作流、条件与重启等独特机制,并彻底转变算法构建思维。
  • Blub 悖论:只用过较弱语言的程序员无法理解 Lisp 的优势,因为他们缺乏识别自身语言缺陷的概念框架。
  • 宏(macro)是 Lisp 的杀手锏:与 C/Rust/Swift 的宏不同,Lisp 宏可以创建新的语言构造,而不仅仅是消除样板代码。
  • 宏 vs 函数:函数的参数会被立即求值,而宏将参数视为未求值的纯数据,从而允许在编译阶段进行代码变换。
  • 同像性(homoiconicity):Lisp 的代码和数据都用列表表示,这种一致性使得宏能够像操作数据一样操作代码,实现“代码生成代码”。
  • 扩展语言:通过宏,程序员可以根据具体问题领域定制语言,实现更简洁、更表达力的代码。
  • 学习 Lisp 的长期收益:即使最终不使用 Lisp,你也会获得关于编程语言能力的全新视角,成为更好的程序员。

意义与影响

这篇文章不仅是对 Lisp 特性的科普,更是对编程本质的反思。它揭示了为何 Lisp 虽然古老,却至今仍在人工智能、语言设计、教育等领域保持影响力。Lisp 所倡导的“代码即数据”理念,直接启发了现代语言的宏系统(如 Rust 的过程宏、Elixir 的宏)和领域特定语言(DSL)的设计。文章强调的“可编程编程语言”概念,挑战了传统语言固定语法的边界,鼓励程序员不仅作为使用者,更作为语言创造者来思考。

从实践角度看,Lisp 的宏和同像性为复杂问题的抽象提供了无与伦比的灵活性,让程序员能够用更少的代码表达更复杂的逻辑。这种能力在快速原型开发、符号计算、甚至操作系统开发中都有重要应用。对于希望突破思维定式的开发者而言,学习 Lisp 是一次深刻的思维训练——它教会你如何通过改变语言本身来适应问题,而不是反过来。正如 Paul Graham 所指出,Lisp 的威力很难被未曾体验过的人理解,但一旦尝到这种自由,你就再也无法回到从前。

查看原文 →scotto.me