Hacker News 中文摘要

RSS订阅

Racket友好入门指南 -- A Friendly Introduction to Racket

文章摘要

本文介绍了Racket语言(Lisp方言)的核心特性:代码即数据、括号作为纯结构、程序可编写程序。回顾了Lisp自1958年诞生以来的历史,强调其开创了垃圾回收、一等函数、REPL、条件表达式和同像性等现代编程概念。

文章总结

Racket友好入门指南

2026年8月11日

"学习Lisp的价值在于,当你最终理解它时,会获得深刻的启迪体验。"——埃里克·S·雷蒙德

欢迎。今天你将学习编程史上最古老、最独特的语言家族之一。这是一种代码即数据、括号即纯粹结构、程序可以编写程序的语言。本教程结束时,你将编写出自己的语法。

一点历史

Lisp诞生于1958年,由约翰·麦卡锡在麻省理工学院发明。它是仍在使用的第二古老的高级语言(仅比1957年的Fortran晚一年)。Python诞生于1991年,JavaScript在1995年。Lisp比它们早了30多年,许多我们现在认为"现代"的概念都诞生于此:

  • 垃圾回收——为Lisp发明
  • 一等函数——将函数作为参数传递,如今已成为标准
  • REPL——交互式读取-求值-打印循环,Python、Node和Julia都拥有,始于Lisp
  • 作为表达式的条件语句——返回值的if
  • 同像性——代码本身就是语言的数据结构。这是最重要的概念,我们最后会回到这一点。

几十年来,Lisp一直是人工智能的语言。70年代和80年代,有专门为直接运行Lisp而设计的物理计算机:Symbolics和LMI制造的Lisp机器。随后"AI寒冬"来临,资金枯竭,Lisp从明星语言变成了小众语言。

但有趣的想法不会消亡——它们会变异,这正是Lisp之美的一部分。

从Lisp到Scheme再到Racket

1975年,杰拉德·萨斯曼和盖伊·斯蒂尔创建了Scheme:一种极简、优雅、近乎数学化的Lisp。Scheme成为学术界教授编程的首选语言(传奇著作《计算机程序的构造和解释》就是用Scheme编写的)。

1995年,马蒂亚斯·费莱森团队创建了PLT Scheme,这是一种专为教育和编程语言研究设计的Scheme。2010年更名为Racket,如今它已远不止是Scheme:它是一种用于构建语言的语言。其非官方座右铭是"语言导向编程":如果你的问题需要自己的语言,Racket让你一个下午就能构建一个。

| 年份 | 事件 | |------|------| | 1958 | 麦卡锡在麻省理工学院发明Lisp | | 1975 | 萨斯曼和斯蒂尔创建Scheme | | 1984 | Common Lisp标准化 | | 1995 | PLT Scheme(现Racket)诞生 | | 2007 | Clojure诞生(JVM上的Lisp) | | 2010 | PLT Scheme更名为Racket | | 今天 | 你,正在阅读本文,即将编写括号 |

今天谁在使用Lisp?

比你想象的更多人:

  • Clojure 在银行、航空公司和初创公司的生产环境中运行(拉丁美洲最大的数字银行Nubank运行在Clojure上)
  • Common Lisp(使用SBCL编译器)仍然活跃在专家系统、航班规划(ITA Software,被谷歌收购,为Google Flights提供支持)和科学计算领域
  • Emacs Lisp——数百万人每天都在运行Lisp而不自知,因为他们的编辑器就是一个Lisp解释器
  • Guile/Guix——整个Linux发行版完全用Scheme配置
  • Racket 拥有自己的年度会议(RacketCon),活跃的学术和艺术社区,用于语言研究、形式验证(Rosette)、排版出版(Pollen)和全球教育
  • 新的Lisp不断涌现:Fennel(编译为Lua的Lisp,在游戏开发中流行)、Janet、Hy(Python之上的Lisp)

安装(5分钟)

前往 https://racket-lang.org 下载适合你系统的安装程序(Linux、macOS、Windows)。打开随附的DrRacket环境。

DrRacket有两个区域:顶部编写定义(你的程序),底部有REPL用于实时实验。在定义区域的第一行,写入:

```

lang racket

```

这行告诉Racket你使用哪种语言(记住:Racket是一个语言工厂,所以你必须选择一种)。

如果你更喜欢终端:racket命令提供REPL,raco是包管理器和工具命令。

在REPL中尝试:

```

(+ 1 2) 3 (* 3 (+ 2 2)) 12 (string-append "hello " "world") "hello world" ```

Lisp的规则可以用一句话概括:

一切都是 (操作符 参数1 参数2 ...)。始终如此。没有例外。

没有需要记忆的运算符优先级,没有任何特殊语法。(+ 1 2)做加法,(if ...)做判断,(define ...)做命名。那些初看令人生畏的括号,实际上恰恰是任意规则的完全缺失。一周后,你就不会再注意到它们了。

定义和函数

```racket

lang racket

(define pi-approx 3.14159) (define (circle-area r) (* pi-approx r r)) (circle-area 2) ; => 12.56636 ```

  • define加名称创建常量
  • define(名称 参数...)创建函数
  • 注释以;开头

匿名函数使用lambda(没错,就是1930年代丘奇λ演算中的那个lambda,它是这一切的理论祖先):

racket (lambda (x) (* x x)) ; 一个没有名字的函数 ((lambda (x) (* x x)) 5) ; => 25,直接应用

列表:Lisp的核心

Lisp代表"列表处理"。列表是基本结构:

racket (list 1 2 3) ; => '(1 2 3) '(1 2 3) ; 同上,"引号" (first '(1 2 3)) ; => 1 (rest '(1 2 3)) ; => '(2 3) (cons 0 '(1 2 3)) ; => '(0 1 2 3) (length '(a b c)) ; => 3

注意引号'。它告诉Racket:不要求值,这是数据。记住这个细节——它是通往最终技巧的大门。

高阶函数

这是Racket的闪光点。将函数传递给其他函数是最自然不过的事:

racket (map (lambda (x) (* x x)) '(1 2 3 4 5)) ; => '(1 4 9 16 25) (filter even? '(1 2 3 4 5 6)) ; => '(2 4 6) (foldl + 0 '(1 2 3 4 5)) ; => 15

map转换,filter筛选,foldl累积。有了这三个函数,你可以在不写任何for循环的情况下解决大多数列表问题。

递归:螺旋式思考

在Lisp中,你不思考"重复N次",而是思考"基本情况是什么,以及如何向它靠近":

racket (define (factorial n) (if (= n 0) 1 (* n (factorial (- n 1))))) (factorial 5) ; => 120

为了让事情更直观,我们来画点东西。Racket内置了图形库:

```racket

lang racket

(require 2htdp/image) (define (sierpinski level) (if (= level 0) (triangle 8 "solid" "purple") (let ([t (sierpinski (- level 1))]) (above t (beside t t))))) (sierpinski 6) ```

将其粘贴到DrRacket中,点击运行,观察谢尔宾斯基三角形出现在屏幕上。

压轴大戏:编写代码的代码

还记得引号'吗:它将代码变成数据。看:

racket '(+ 1 2) ; => 列表(+ 1 2),而不是数字3 (first '(+ 1 2)) ; => 符号+ (eval '(+ 1 2)) ; => 3。你刚刚将数据作为代码求值了

你的程序是一个列表。你可以构建列表。因此:你可以用程序构建程序。这就是同像性,也是为什么Lisp拥有真正的宏——不是C语言中的文本宏,而是在任何代码运行之前,接收代码并返回代码的函数。

Racket没有while循环?让我们发明一个:

racket (define-syntax-rule (while condition body ...) (let loop () (when condition body ... (loop)))) (define counter 0) (while (< counter 5) (displayln counter) (set! counter (+ counter 1)))

你刚刚扩展了语言!在Lisp中,语法是你的。

艾伦·凯称Lisp为"软件的麦克斯韦方程组":一个微小的核心,从中可以推导出一切。

下一步是什么?

评论总结

根据评论内容,总结如下:

主要观点与论据:

  1. 对Racket/Lisp的兴趣与尝试意愿(评论1、4、6)

    • 用户对Racket应用场景好奇,但发现多为库和开发工具。
    • 有用户表示会尝试用Racket写Black Jack游戏。
    • 关键引用:em-bee "any time the topic of racket comes up, i wonder if there are any interesting apps i could explore. but all i find is libraries and dev tools";mcbk2142 "I will try writing Black Jack in it!"
  2. 对教程友好性的批评(评论5)

    • 认为该教程并非友好入门,而是“速通”,假设读者已了解lambda和语法规则。
    • 关键引用:fn-mote "this is not a friendly intro. It is a speedrun... I don’t expect it to assume that I know what lambda is"
  3. 对语言实用性的质疑(评论7、10)

    • 认为Racket/Lisp在实际中很少被使用,可能因部署不便。
    • 有评论指出Lisp在AI领域早已被Prolog取代,美国因技术债务仍在使用。
    • 关键引用:zerr "nobody is using it in the wild... cumbersome deployment options";ux266478 "Lisp had fallen from relevance before then... Prolog displaced it in the late 1970s"
  4. 对语言特性的正面评价(评论2、8)

    • 提及Lisp的continuations机制用于错误恢复,以及宏和语言导向编程的灵活性。
    • 关键引用:perrygeo "Lisp continuations allow for graceful error recovery";usxr1515 "Racket's approach to macros and language-oriented programming is one of the things I keep coming back to as a reference"
  5. 其他技术讨论(评论3、9、11)

    • 有用户认为Scheme的唯一吸引力是热重载;有用户展示Racket的语法特性;有用户提及Janet语言。

平衡性总结: - 正面观点:对Racket/Lisp的兴趣、语言特性(宏、continuations)的认可。 - 负面观点:教程不友好、实际使用率低、部署困难、在AI领域已被Prolog取代。 - 中立观点:部分用户持观望或尝试态度,也有用户关注其他类似语言(如Janet)。