user=> (+ 2 3)
5
user=> (defn factorial [n]
(if (= n 0)
1
(* n (factorial (dec n)))))
#'user/factorial
user=> (factorial 10)
3628800
user=>
启动 REPL 后(如上一章所述),您可以通过在 REPL 中输入 Clojure 表达式并按 ENTER 键来评估它们。
user=> (+ 2 3)
5
user=> (defn factorial [n]
(if (= n 0)
1
(* n (factorial (dec n)))))
#'user/factorial
user=> (factorial 10)
3628800
user=>
在每个表达式下,我们看到表达式评估的结果。这就是 REPL 的作用:对于我们提交给它的每个表达式,REPL 会Read(读取)它,Evaluate(评估)它,然后Print(打印)结果,所有这些都在一个Loop(循环)中进行。
如果您正在学习 Clojure,请花一些时间在 REPL 中进行实验。它提供的快速反馈循环为学习提供了非常有效的环境。 |
尽管以上示例非常基础,但您可以用这种方式运行功能齐全的 Clojure 程序。Clojure 的设计使它的 REPL 环境提供了语言的全部功能:您实际上可以运行任何现有的 Clojure 程序,只需将源文件的内容按正确的顺序粘贴到 REPL 中即可。
提示:在 REPL 旁边使用编辑器 在终端窗口中编辑 Clojure 代码可能会很繁琐;在这种情况下,一个简单的技巧是在您选择的具有语法感知 Clojure 模式的文本编辑器中编写代码,并将代码从编辑器复制粘贴到 REPL 终端窗口中。以下是一个示例(使用的编辑器是Atom)。
在本指南的增强您的 REPL 工作流程一章中,我们将看到使用 REPL 的更符合人体工程学的配置。但是,这种极简的设置足以满足本教程的范围,并且对于掌握基础知识很重要。 |
考虑以下评估
user=> (println "Hello World")
Hello World
nil
这很奇怪:与之前的示例不同,它看起来像评估 (println "Hello World")
表达式产生了两个结果:Hello World
和 nil
。
这是因为 println 函数会将它的参数打印到标准输出,但会返回 nil。因此,我们在表达式下看到的两行本质上是不同的
Hello World
是评估表达式的副作用(打印到标准输出):打印是我们的代码完成的。
nil
是评估表达式的结果:打印是 REPL 完成的。
到目前为止,我们只调用了我们在 REPL 中手动定义的代码(例如我们上面定义的 factorial
函数)。但 REPL 也允许您使用预先存在的 Clojure 代码,即 Clojure 库。[1] 给定一个命名空间为 my.name.space
的 Clojure 库,您可以评估 (require '[my.name.space])
来使该库的代码加载并可在 REPL 中使用。
例如,clojure.string
是一个与 Clojure 捆绑在一起的库,用于操作文本。让我们要求 clojure.string
并调用它的 clojure.string/upper-case
函数
user=> (require '[clojure.string])
nil
user=> (clojure.string/upper-case "clojure")
"CLOJURE"
require
还允许我们为 clojure.string
命名空间定义一个别名,方法是在后面添加一个 :as
子句。这使我们能够更简洁地引用在 clojure.string
命名空间中定义的名称
user=> (require '[clojure.string :as str])
nil
user=> (str/upper-case "clojure")
"CLOJURE"
最后,如果我们非常懒惰,不想输入别名,我们可以添加一个 :refer
子句
user=> (require '[clojure.string :refer [upper-case]])
nil
user=> (upper-case "clojure")
"CLOJURE"
REPL 还可以用于查找 API 文档,方法是使用 clojure.repl
库。在 REPL 中评估以下表达式
user=> (require '[clojure.repl :refer :all])
nil
此表达式使在 clojure.repl
命名空间中定义的所有名称在 REPL 中可用。
您可以通过评估 (doc MY-VAR-NAME)
来打印给定 Var 的 API 文档。
user=> (doc nil?)
-------------------------
clojure.core/nil?
([x])
Returns true if x is nil, false otherwise.
nil
user=> (doc clojure.string/upper-case)
-------------------------
clojure.string/upper-case
([s])
Converts string to all upper-case.
nil
您还可以使用 source
查看用于定义 Var 的源代码。
user=> (source some?)
(defn some?
"Returns true if x is not nil, false otherwise."
{:tag Boolean
:added "1.6"
:static true}
[x] (not (nil? x)))
nil
您可以使用 dir
列出给定命名空间中所有 Var 的名称。让我们对 clojure.string
命名空间执行此操作
user=> (dir clojure.string)
blank?
capitalize
ends-with?
escape
includes?
index-of
join
last-index-of
lower-case
re-quote-replacement
replace
replace-first
reverse
split
split-lines
starts-with?
trim
trim-newline
triml
trimr
upper-case
nil
另一个例子,让我们使用 dir
来查看 clojure.repl
本身都有什么
user=> (dir clojure.repl)
apropos
demunge
dir
dir-fn
doc
find-doc
pst
root-cause
set-break-handler!
source
source-fn
stack-element-str
thread-stopper
nil
我们认识到到目前为止我们使用的 doc
、source
和 dir
操作。
如果您不记得某个 Var 的确切名称,您可以使用 apropos
搜索它
user=> (apropos "index")
(clojure.core/indexed? clojure.core/keep-indexed clojure.core/map-indexed clojure.string/index-of clojure.string/last-index-of)
user=> (find-doc "indexed")
-------------------------
clojure.core/contains?
([coll key])
Returns true if key is present in the given collection, otherwise
returns false. Note that for numerically indexed collections like
vectors and Java arrays, this tests if the numeric key is within the
range of indexes. 'contains?' operates constant or logarithmic time;
it will not perform a linear search for a value. See also 'some'.
-------------------------
clojure.core/indexed?
([coll])
Return true if coll implements Indexed, indicating efficient lookup by index
-------------------------
clojure.core/keep-indexed
([f] [f coll])
Returns a lazy sequence of the non-nil results of (f index item). Note,
this means false return values will be included. f must be free of
side-effects. Returns a stateful transducer when no collection is
provided.
-------------------------
clojure.core/map-indexed
([f] [f coll])
Returns a lazy sequence consisting of the result of applying f to 0
and the first item of coll, followed by applying f to 1 and the second
item in coll, etc, until coll is exhausted. Thus function f should
accept 2 arguments, index and item. Returns a stateful transducer when
no collection is provided.
nil
文档仅适用于已要求的库。 例如,如果您没有要求
|