diff options
| -rw-r--r-- | content/article/clj0.md (renamed from content/article/tutorial-clj-0.md) | 3 | ||||
| -rw-r--r-- | content/article/clj1.md (renamed from content/article/tutorial-clj-1.md) | 3 | ||||
| -rw-r--r-- | content/article/clj2.md (renamed from content/article/tutorial-clj-2.md) | 25 | ||||
| -rw-r--r-- | content/article/clj3.md (renamed from content/article/tutorial-clj-3.md) | 5 |
4 files changed, 26 insertions, 10 deletions
diff --git a/content/article/tutorial-clj-0.md b/content/article/clj0.md index 444ba2aa..2473f968 100644 --- a/content/article/tutorial-clj-0.md +++ b/content/article/clj0.md @@ -1,7 +1,8 @@ +++ title = 'Coffee Break Clojure, Vol.0' subtitle = '初识 Clojure 与 Lisp' -slug = 'tutorial-clj-0' +slug = 'clj0' +aliases = '/article/tutorial-clj-0/' tags = ["Lisp","编程"] categories = '茶歇蔻芥' date = 2026-09-15 22:58:43 diff --git a/content/article/tutorial-clj-1.md b/content/article/clj1.md index 6ead5a50..3f043afb 100644 --- a/content/article/tutorial-clj-1.md +++ b/content/article/clj1.md @@ -1,7 +1,8 @@ +++ title = 'Coffee Break Clojure, Vol.1' subtitle = '准备工具' -slug = 'tutorial-clj-1' +slug = 'clj1' +aliases = ['/article/tutorial-clj-1'] tags = ["Lisp","编程"] categories = '茶歇蔻芥' date = 2026-09-19 01:45:49 diff --git a/content/article/tutorial-clj-2.md b/content/article/clj2.md index 3bfd5983..a5d6207c 100644 --- a/content/article/tutorial-clj-2.md +++ b/content/article/clj2.md @@ -1,7 +1,8 @@ +++ title = 'Coffee Break Clojure, Vol.2' subtitle = "Forms O' Plenty" -slug = 'tutorial-clj-2' +slug = 'clj2' +aliases = '/article/tutorial-clj-2/' tags = ["Lisp","编程"] categories = '茶歇蔻芥' date = 2026-09-25 18:43:53 @@ -129,6 +130,19 @@ a (+ 1 num)) ``` +你可能注意到了 Clojure 函数和非 Lisp 语言的另一个区别:没有 `return` 语句。函数如果有多个并列的形式,就会以最后一个形式的值作为函数的返回值。 + +做个习题,下面这段函数调用为什么返回了 `nil`? + +```clojure +(defn chatty-add [a b] + (let [result (+ a b)] + result + (println result))) + +(chatty-add 1 2) ;; => nil +``` + ## Lambda 形式 Lambda 形式类似 JavaScript 里的立即执行函数,也就是定义一个匿名函数,然后立马执行它,这样就可以限定变量的作用域。 @@ -189,18 +203,17 @@ Lambda 形式的操作符不是指向函数的符号,就是函数本身。 你发现了吗?我们做了一步完全多余的运算。根本不需要计算 `(> a 1)` 为 `false`,只要算出 `(> b 1)` 为 `true`,就可以算出整个 `or` 形式的值为 `true`,因为逻辑运算或只要求其中一个值为真。 -如果 `or` 是函数,就必须做那一步多余的运算,否而得不到值,无法调用函数。然而,有些运算是有副作用的,比如从消息队列中取出一条消息,会导致其他人无法再次从队列中取到它,若 `or` 运算丢弃了这条消息,只采用了其中一条,数据就丢失了。 +如果 `or` 是函数,就必须做那一步多余的运算,否而得不到值,无法调用函数。然而,有些运算是有副作用的,比如从消息队列中取出一条消息,会导致其他人无法再次从队列中取到它,若 `or` 运算丢弃了这条消息,数据就丢失了。 那怎么办呢?有什么办法可以让参数不被预先求值吗? -有的,答案就是宏(macro)。宏这个机制被不少语言借鉴,比如 Rust 和 Haskell(在 Haskell 里叫 Template,模板),其实本质就是对还没求值的列表做预处理。 +答案就是宏(macro)。宏这个机制被不少语言借鉴,比如 Rust 和 Haskell(在 Haskell 里叫 Template,模板),其实本质就是对还没求值的列表做预处理。 定义宏就是定义一系列对列表做变换的规则,宏作为形式的操作符时,会先进行宏展开(macroexpand),然后对展开的结果求值。宏展开之前,所有的列表都不会被求值。 我们来看看 `or` 这个宏的定义: ```clojure - (defmacro or ([] nil) ([x] x) @@ -245,7 +258,7 @@ Lambda 形式的操作符不是指向函数的符号,就是函数本身。 ``` <details> - <summary>如果 `fn` 是函数的解释</summary> + <summary>如果 <code>fn</code> 是函数的解释</summary> 首先对 `[a b c]` 求值,解释器会发现 `a` 这个符号不存在,然后报错。 @@ -351,7 +364,7 @@ Clojure 没有用编译器实现解构,而是用 `destructure` 函数实现的 现在你应该知道求值 Clojure 形式时,解释器底下大概都发生了什么,你应该也熟悉了一些基本的函数、宏和特殊形式,比如 `let` `if` 和 `fn`,可以写一些简单的 Clojure 程序了。 -其实除了本文提到的四种形式,Clojure 还可以用特定类型的数据作为操作符,也可以当作一种类型的形式。这要留到下篇讲了。 +其实除了本文提到的四种形式,Clojure 还可以用特定类型的数据作为操作符(比如用一个集合做操作符,用于查看参数是否存在于集合内),也可以当作一种类型的形式。这要留到下篇讲了。 下一篇我们要了解 Clojure 里的集合数据类型,分别是我们已经见过的列表(list)和向量(vector),此外还有集合(set)和映射(map)。我们还会讲到如何操作这些集合,包括遍历和筛选等等。我们还会了解到惰性序列(Lazy sequence),然后你就可以写程序处理相对复杂的数据,并且能够到同时做到语法简洁和高性能。这些都是后话了。 diff --git a/content/article/tutorial-clj-3.md b/content/article/clj3.md index 237d8527..80475c32 100644 --- a/content/article/tutorial-clj-3.md +++ b/content/article/clj3.md @@ -1,7 +1,8 @@ +++ title = 'Coffee Break Clojure, Vol.3' subtitle = '只用圆括号怎么够?' -slug = 'tutorial-clj-3' +slug = 'clj3' +aliases = '/article/tutorial-clj-3' tags = ["Lisp","编程"] categories = '茶歇蔻芥' date = 2026-09-25T20:17:41+08:00 @@ -251,7 +252,7 @@ Clojure 的映射写起来和 JSON 很像。 :key3 nil} ``` - +https://www.brainonfire.net/files/seqs-and-colls/main.html ## 井号和集合 |
