diff options
Diffstat (limited to 'content/article/tutorial-clj-1.md')
| -rw-r--r-- | content/article/tutorial-clj-1.md | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/content/article/tutorial-clj-1.md b/content/article/tutorial-clj-1.md new file mode 100644 index 00000000..415a6ae8 --- /dev/null +++ b/content/article/tutorial-clj-1.md @@ -0,0 +1,62 @@ ++++ +title = 'Coffee Break Clojure, Vol.1' +subtitle = '读取-求值-打印-循环' +slug = '' +tags = [] +categories = '' +date = 2026-09-15T23:48:00+08:00 +draft = true +toc = true ++++ + +[上一篇](/article/tutorial-clj-0)我们了解了 Lisp 中「代码即数据」的本质,知道了不求值(Eval)的列表就是数据,被求值的列表就是代码,而代码可以像数据一样经过任意的变换之后再求值。 + + +## Heat up the REPL + +正式开始之前,你需要先安装 Java 和 [Clojure](https://clojure.org/guides/install_clojure)(因为 Clojure 运行在 JVM 之上),之后就可以在终端输入 `clojure`,按下回车之后便会看到新的命令提示符: + +``` +Clojure 1.12.6 +user=> +``` + +在 Lisp 的世界里,这一般被称作 REPL,全称是:Read-Eval-Print-Loop(读取-求值-打印-循环)。顾名思义,它读取用户输入,求值,打印这个值,然后循环。有趣的是,在 Common Lisp 等方言中,你可以用一行代码启动最原始的 REPL: + +```lisp +(loop (print (eval (read)))) +``` + +Clojure 不能这样写,因为 `loop` 的用法不同。不过把 `loop` 换成 `while` 就好了,效果差不多。试试看,在你的 REPL 里输入这段代码: + +```clojure +(while true (println (eval (read)))) +``` + +然后你就会在 REPL 里获得一个简陋的子 REPL。不难发现,REPL 和 [Shell](https://en.wikipedia.org/wiki/Shell_(computing)) 非常类似,前者允许用户用命令行界面与编程语言交互,后者允许用户用命令行界面与操作系统交互。或者说,Shell 语言就是用来跟操作系统交互的编程语言,而 Shell 程序就是 Shell 语言的 REPL。 + +现在,按下 `Ctrl + D` 退出子 REPL,回到*真正的* REPL 里。 + +在开启你的 Clojure/Lisp 旅程之前,务必和 REPL 打好关系。我记得我刚开始写 Clojure 的时候还像个麻瓜一样写完代码,保存,然后执行整个文件甚至整个项目。这很折磨,而且让 Clojure 感觉上就是个语法更小众的普通编程语言。 + +REPL 不仅仅是跟 Clojure 交互的媒介,还是与你自己的代码交互的媒介,也可以是用户与你的代码交互的媒介。 + +Lisp 常见的编程实践叫作交互式编程(Interactive Programming),允许程序员一边写代码一边与已经写好的代码交互。原理其实很简单,每写好一段代码,都把代码发送到 REPL 里求值,函数定义、变量和各种状态被加载到 REPL 中,就可以使用之前已经定义好的符号继续编程。 + +最原始的交互式编程是:电脑上一边打开编辑器,另一边打开终端运行 REPL,每写一段代码就复制粘贴到 REPL 中。不过这太不优雅了,Emacs 的 [SLIME](https://github.com/slime/slime) 和 Neovim 的 [Conjure](https://github.com/Olical/conjure)[^1] 允许程序员直接在编辑器内部对代码求值,它们用某种协议把代码发送给 REPL 进程(或 REPL 服务器),随后 REPL 把结果返回给编辑器。 + +这有什么用呢?比方说你想要临时测一测你写的某个函数是否正常工作,或者看看某个库提供的函数返回的具体的数据格式,你不需要手动把他们的依赖库以及你已经在文件里定义好的变量手动复制到 REPL 里,也不需要手动执行整个程序,只需要按几个快捷键,结果就是呈现在你的编辑器里,显示在你的代码旁边。 + +如果你写过前端,你一定对热重载(Hot Relaod)不陌生。REPL 就是 Lisp 通用的热重载机制。不需要重启系统,每个改动都可以直接加载到 REPL 里。 + +REPL 作为用户界面也大有用处。在 1988 年,运行在太空中的一个 Lisp 程序陷入了死锁,名叫 Ron Garret 的 Lisp 程序员正是用 [REPL](https://corecursive.com/lisp-in-space-with-ron-garret/#a-repl-on-a-spacecraft) 查询程序状态并发送指令,解决了运行在二百四十万公里以外的某个程序的 Bug。正如程序员可以一边写代码一边运行刚写完的代码,用户也可以通过 REPL 与正在运行的程序交互。 + +## Conjure up your program + +--- + +下一篇文章将重点关注形式(form)的诸多种类:函数(function form)、宏(macro form)和特殊形式(special form)。 + + +[^1]: Conjure 还支持 Python、JavaScript、PHP、R、Lua、Rust 等语言。 + |
