Clojure 是一门运行在 JVM 上的 Lisp 方言。我的学习方式是通过看官网的Getting Started。
Mac OS 下配置开发环境
用 homebrew 先安装 Java:
brew install java
然后安装 Clojure 的 REPL 解释器:
brew install clojure
暂时只安装了这么多,没有安装 Leiningen 和 Boot。
字面值(Literals)
Clojure 有下面几种数据类型:
;; 数字类型
42 ; Long - 64 bits 整数
6.022e23 ; Double - 64 bits 浮点数
42N ; BigInt - 高精度整数
1.0M ; BigDecimal - 高精度定点数
22/7 ; 分数
;; 字符类型
"hello" ; 字符串
\e ; 字符
;; 其他类型
nil ; 空值
true ; Boolean 类型(还有 false)
#"[0-9]+" ; 正则表达式
:alpha ; 关键字
:release/alpha ; 带 namespace 的关键字
map ; 符号(symbol)
+ ; 符号可以是标点符号
clojure.core/+ ; Namespaced symbol
;
表示注释,两个分号表示首行。
另外还有四种 collection 类型:
‘(1 2 3) ; 列表(list)
[1 2 3] ; 向量(vector)
#{1 2 3} ; 集合
{:a 1, :b 2} ; map
求值(Evaluation)
Clojure 不同于传统的 源代码 -> 编译 -> 运行的方式,Clojure 的每一个表达式都能够求值,通过 Reader 读取用户输入,然后编译到 JVM 的字节码,然后在 JVM 上运行求值。
结构(Structure)和语义(Semantics)
示意图种的绿字表示符号,蓝色字表示语义。大部分 Clojure 的表达式对自身求值,除了符号和列表。
如图所示,(+ 3 4) 读入一个列表,包含一个符号(+)和两个数字(3、4),列表中的第一个元素(图片中 + 所在的位置)被称作“function position“,表示要调用的函数。
Delaying evaluation with quoting
不知道这里怎么翻译,简单的说就是用引号表示“推迟求值”,暂时不求出来。
举个例子:
user=> ‘x
x
这里 x 前面加了一个引号,解释器不会对这个符号进行求值,而是保留了这个符号。
我们还可以用引号表示一个列表(list),而不进行求值:
user=> ‘(1 2 3)
(1 2 3)
REPL
REPL(Read-Eval-Print-Loop) 由以下四步组成:
- 读出表达式
- 对 #1 的表达式进行求值
- 输出 #2 中求出的值
- 回到最开始
探索 REPL
绝大多数 REPL 环境都有一些小技巧可以交互使用。比如:
*1
表示上一个结果*2
表示上上个结果*3
表示上上上个结果
user=> (+ 3 4)
7
user=> (+ 10 *1)
17
user=> (+ *1 *2)
24
还有一个 namespace 叫 clojure.repl
包含了标准 Clojure 库,里面有几个有用的函数,首先我们要载入这个库:
(require ‘[clojure.repl :refer :all])
然后我们就可以用这几个函数了:doc
、find-doc
、apropos
、source
、dir
这几个函数的具体作用可以在官网上看,我就不列举出来了。
Clojure 基础
def
如果你想要在 REPL 环境中用你求值后的值,可以这样写:
user=> (def x 7)
#‘user/x
然后我们就把符号(symbol)x
和值(var) 7
关联起来了,接下来就可以直接用这个符号了:
user=> (+ x x)
14
需要注意的是这个符号默认是 user
这个namespace 中的符号。我们调用的时候也默认实在 user
这个 namespace 中。
打印
Clojure 提供了四种打印函数:
println
是给人读的带换行的打印函数prn
是给机器读的带换行的打印函数print
是给人读的不带换行的打印函数pr
是给机器读的不带换行的打印函数
简单的说,给人读的会对字符进行转义,而且会把其中的表达式的值求出来:
user=> (println "This is a\ttest" (+ 1 2 3))
This is a test 6
机器读的不会转义,而且也不会把表达式的值求出来。