惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
Recorded Future
Recorded Future
Microsoft Azure Blog
Microsoft Azure Blog
M
MIT News - Artificial intelligence
酷 壳 – CoolShell
酷 壳 – CoolShell
I
InfoQ
博客园 - 司徒正美
Stack Overflow Blog
Stack Overflow Blog
Simon Willison's Weblog
Simon Willison's Weblog
爱范儿
爱范儿
D
Darknet – Hacking Tools, Hacker News & Cyber Security
V
Visual Studio Blog
H
Help Net Security
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
B
Blog RSS Feed
美团技术团队
G
GRAHAM CLULEY
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
腾讯CDC
G
Google Developers Blog
Cyberwarzone
Cyberwarzone
T
Tenable Blog
A
About on SuperTechFans
WordPress大学
WordPress大学
Engineering at Meta
Engineering at Meta
L
Lohrmann on Cybersecurity
C
Cisco Blogs
K
Kaspersky official blog
Recent Announcements
Recent Announcements
Vercel News
Vercel News
C
Cybersecurity and Infrastructure Security Agency CISA
有赞技术团队
有赞技术团队
P
Privacy & Cybersecurity Law Blog
Hugging Face - Blog
Hugging Face - Blog
S
Schneier on Security
Apple Machine Learning Research
Apple Machine Learning Research
Cloudbric
Cloudbric
Scott Helme
Scott Helme
Google Online Security Blog
Google Online Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Attack and Defense Labs
Attack and Defense Labs
Google DeepMind News
Google DeepMind News
N
News and Events Feed by Topic
D
Docker
U
Unit 42
S
Security @ Cisco Blogs

硅上观道・我的个人技术博客

函数式心法 (3):巧用柯里化和部分应用 函数式心法 (2):理解运用高阶函数 打造 NixOS 开发环境 (2):NixOS学习与配置入门指南 打造 NixOS 开发工作流 (1):为什么选择 NixOS Haskell 心法 (1):初识 - 为何学、学什么和怎么学 Clojure 笔记 (1):语言生态介绍和环境配置 前端笔记 (1):ES 标准和 ES6+ 变量定义方法 当我们发现毕生追求的知识在AI面前毫无价值时,如何重建存在的意义? 5 月 28 日 DeepSeek R1 模型完成小版本试升级并开源,具体有哪些提升? 信息闭塞和被信息洪流冲刷,哪个弊端更大?谈错误信息的危害性 Rust CLI 实战:手搓微型 grep (4) 交互式处理错误文件名问题 Rust CLI 实战:手搓微型 grep (3) 更优雅的错误处理 Rust CLI 实战:手搓微型 grep (2) 实现软件第一版 Rust CLI 实战:手搓微型 grep (1) 新建项目 学计算机有什么好的获取学习资料的方法?掌握高效的资料收集技巧 有哪些看起来很高端的技术其实原理很暴力很初级?浅析CDN内容分发网络原理 学习编程可以为自己带来什么?- 理论与实践的紧密结合 长文 - 大一技术成长复盘:课程、竞赛与开源之旅 推荐一个IDE中的AI工具 - CodeGeex插件和AI辅助编程 关于本站 - 一篇旧文章,我对本站内容更新计划的最初想法 读书笔记:读庄子《齐物论》,探寻真正的自我 读书笔记 - 单向度的人:核心思想,内容解析以及我的感悟 一篇时评写作练习:矛盾与救赎 - 关于行善
Clojure 笔记 (2):基本语法结构和 REPL 驱动编程
硅上观道 · 2025-06-22 · via 硅上观道・我的个人技术博客
技术教程

上篇文章我们聊了 Clojure 语言的基本特性和语言生态,这篇文章我想讲讲 Clojure 的语法,以及最有特色的 REPL 驱动编程。Clojure 基于 S 表达式(S-expression)的语言特性,使其天然具备了实现强大开发工具(如 REPL)和语言扩展能力(如宏)的基础,带来了许多独特且高效的开发体验。

上篇文章我们聊了 Clojure 语言的基本特性和语言生态,这篇文章我想讲讲 Clojure 的语法,以及最有特色的 REPL 驱动编程。

欢迎查看这个系列的上一篇文章,也欢迎关注我的全栈开发笔记系列专栏,我将更新更多精彩内容。


Clojure 一系列神奇的特性,比如非常好用的 REPL 驱动开发、基于宏的元编程等。

究竟是什么带来了这一系列可以极大提高开发者体验的特性呢?我希望在这篇文章初探一下。

1. Clojure 的基本语法结构

如果你看过 Lisp 语系的语言,一定会对其满屏的()小括号印象深刻。

不同于 C 系的语言普遍使用{}来划分代码段,Lisp 系语言使用的是层层叠叠的小括号。

我们来看一个 Clojure 官网提供的示意图:

Clojure的S表达式 (Source: clojure.org)

这个示意图上使用了一个非常基本的 Clojure 表达式:

这和其他语言的3 + 4的含义是一样的,最后计算出的结果也是 7。

用 Clojure 的语法概念来分析,+加号一个符号,这个符号代表的是加法函数。后续的数字34,是传入函数的参数。

从另一个角度说,这整个表达式不仅仅表示了一个函数。如果我们不考虑这行代码在执行时的作用,只看字面形态,这个()由小括号括起来的结构实际上也可以代表 Clojure 原生数据结构:列表(List)。

也就是说,每个 Clojure 的表达式实际上也是一个 List,我们可以去评估这个表达式的执行结果,也可以像操作一个列表一样来操作这个表达式。

这个特性,实际上对于 Clojure 实现方便的宏编程有着重要的作用。当然,要讲到宏,还需要再写 2~3 篇文章,欢迎大家关注我。


2. 独特的代码评估过程

如果你接触过 Java,一定熟悉 Java 的代码评估流程。我们来看一个同样援引自 Clojure 官网的流程图:

Java源代码评估流程图 (Source: clojure.org)

Java 的源代码被编译器javac编译成可以在 JVM 上运行的字节码。

那么,同样作为运行在 JVM 上的语言,Clojure 的策略是什么样的呢?

Clojure独特的评估流程 (Source: clojure.org)

源代码在被编译成字节码前首先经历了一步,就是被Reader读取成了 Clojure 数据结构 ── 也就是上文提到的 List。

这种设计就意味着:

  1. Clojure 代码的最小执行单元不再是源代码文件,而是一个由()括起来的表达式;
  2. 由于源代码文件实际上也被读取成一个个表达式,那么其实完全可以由开发者交互性输入一个个需要的表达式然后执行,这就为 REPL 驱动开发提供了可能;
  3. 由于把源代码转化成数据结构的Reader和编译为字节码的Compiler两个步骤被严格分开,用代码生成代码的思路(也就是宏)成为可能。宏在编译阶段(Compiler)的早期进行展开,而这个编译阶段的输入是 Reader 产生的数据结构。宏展开发生在将数据结构编译成字节码之前;

下面,我们具体重点讨论第二点,也就是 REPL 驱动开发。


3. REPL 驱动开发

所谓 REPL,指的是“Read-Eval-Print-Loop”,也即读取 ── 评估 ── 打印循环。

如果你用过 Python 的 Jupyter Notebook 或者是 Wolfram Mathematica,我相信你一定不会对 REPL 感到陌生。每次需要修改代码时,无需从头到尾执行一遍代码文件,而是可以只执行一个较小的代码片段,立刻看到这个代码片段的执行结果。

事实上,Clojure 的 REPL 要比 Python、Wolfram 语言的 REPL 要好用得多。究其原因,还是因为 Lisp 语系独特的语法结构。

由于任何一个由()小括号括起来的表达式都可以执行,我们可以尝试按照任意顺序、执行任意嵌套层级的表达式。

举一个简单的例子:

这是我配置好的 VSCode + Calva 插件的环境,这是我从一个代码文件中间随便挑出的代码片段:

一段简单的代码示例

我可以随性所欲地执行代码片段看看结果:

使用Calva评估每行代码

这种即时反馈和探索能力,是不是极大地提升了开发体验?


总结来说,Clojure 基于 S 表达式(S-expression)的语言特性,使其天然具备了实现强大开发工具(如 REPL)和语言扩展能力(如宏)的基础,带来了许多独特且高效的开发体验。

今天这篇文章着重讲了 REPL 驱动开发的基本概念。下面几篇文章,我将谈谈 Clojure 的基本数据结构,流程控制,以及函数式风格的高阶函数写法等问题。

关注我,不错过更多有趣的技术博客!