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 環境提供語言的全部功能:你可以透過將來源檔案的內容按正確順序貼到 REPL 中,實際執行任何現有的 Clojure 程式。
提示:在 REPL 旁邊使用編輯器 在終端機視窗內編輯 Clojure 程式碼可能會很繁瑣;遇到這種情況時,一個簡單的技巧是在你選擇的文字編輯器中撰寫程式碼,該編輯器具備支援 Clojure 語法的模式,然後將程式碼從編輯器複製貼上到 REPL 終端機視窗。以下是範例說明(使用的編輯器為 Atom) 在這個指南的提升你的 REPL 工作流程章節中,我們將看到更符合人體工學的 REPL 使用設定。不過,這個極簡主義設定已足夠應付本教學課程的範圍,而且對於精通基礎知識非常重要。 |
考慮以下評估
user=> (println "Hello World")
Hello World
nil
這很奇怪:與前述範例不同,看起來評估 (println "Hello World")
表達式產生了 2 個結果:Hello World
和 nil
。
這是因為 println 函式會將其引數列印到標準輸出,但傳回 nil。因此,我們在表達式下方看到的 2 行在性質上非常不同
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
文件僅提供給已載入的函式庫。 例如,如果你尚未載入
|