天天看點

《Clojure程式設計》——第1章,第1.3節探索Clojure的程式庫

本節書摘來自異步社群《clojure程式設計》一書中的第1章,第1.3節探索clojure的程式庫,作者 【美】stuart halloway , aaron bedra,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

1.3 探索clojure的程式庫

clojure程式設計

clojure代碼通常都被打包在程式庫中。每個clojure庫都屬于某個命名空間,這與java的包非常類似。你可以通過require來加載一個clojure庫。

(require quoted-namespace-symbol)

當你使用require加載了一個名為clojure.java.io的庫時,clojure會在classpath中查找名為clojure/java/io.clj的檔案。試試看。

起頭的單引号(')是必不可少的。它表示對庫名的引用(關于引用的内容參見2.2節“讀取器宏”)。傳回nil表示庫加載成功。如果你想測試一下,可以加載本章的示例代碼examples.introduction。

examples.introduction庫中包含了一個fibonacci數列的實作,這是函數式程式設計語言傳統的“hello world”程式。在4.2節“怎樣偷個懶”中,我們會探索關于fibonacci數列的更多細節。現在,你隻要確定能夠執行這個示例函數fibs即可。你可以在repl中輸入下面的代碼行以擷取前10個fibonacci數。

如果你看到的前10個fibonacci數與此處列出的相同,說明你已經成功安裝了本書的示例。

本書的所有示例都進行了單元測試,測試代碼位于examples/test目錄。本書并未明确包含這些示例的測試本身,但你會發現它們可以作為非常有用的參考。你也可以自己執行lein test指令來運作這些單元測試。

1.3.1 require和use

當你用require加載了一個clojure程式庫,就需要使用命名空間限定的名稱來引用這個庫裡面的内容。你必須這麼寫:examples.introduction/fibs,而不是簡單地寫下fibs了事。下面,確定你新啟動了一個repl1,然後試着輸入。

總要使用完全限定名實在是太啰嗦了。你可以對命名空間使用refer,将其下的所有名稱映射到你的目前命名空間中。

對examples.introduction調用refer,然後确認你能否直接調用fibs了。

為友善起見,clojure的use函數把require和refer合并成了一個步驟。

在新啟動的repl中,你應該能夠順利執行下列代碼。

在使用本書的示例代碼期間,你可以在調用require或use時,使用:reload标記用來強制重新加載一個程式庫。

如果你進行了一些修改,想看看結果如何,但又不想重新啟動repl,那麼:reload标記就能幫上大忙。

1.3.2 查找文檔

通常情況下,你都可以在repl中找到你需要的文檔。最基本的輔助函數2是doc。

試試使用doc來列印str函數的文檔。

doc輸出的第一行包含了目标函數的全限定名稱。接下來的一行包含了可能的參數清單,這是直接從代碼中生成的。“參數命名慣例”中有一些常用的參數名稱,及它們的用途解釋。最後,剩下的那幾行是這個函數的文檔字元串(doc string),當然,如果在函數定義中包含了它們的話。

你可以為自己的函數添加文檔字元串,隻要将它放置在緊接着函數名的位置即可。

有時你想要查閱文檔時,不清楚目标的确切名稱。find-doc會用你傳入的正規表達式或是字元串,找出所有那些調用doc函數得到的輸出能與之比對的東西。

試試用find-doc檢索一下clojure是如何進行reduce的。

reduce用于對clojure容器進行歸納,第3.2.4小節“序列轉換”中讨論了該話題。areduce則作用于java數組,第9.4.2小節“使用java容器”中有關于它的讨論。

參數命名慣例

reduce和areduce的文檔字元串展示了幾個簡練的參數名稱。表1-1列出了一些約定的參數名,以及通常情況下應該如何使用它們。

表1-1 參數名

《Clojure程式設計》——第1章,第1.3節探索Clojure的程式庫

這些名稱看起來似乎過于簡練了,但采用它們有一個很好的理由:“好名稱”往往已經被clojure函數給占用了!盡管從文法角度,參數可以和其他函數重名,但這是一種糟糕的風格:參數會遮蔽函數,當它們同處一室時,後者将會失效。是以,千萬不要把你的引用叫做ref、把代理叫做agent,或者把數量叫做count。這些名稱代表的是函數。

clojure自己的源碼中,很多都是用clojure本身寫成的,閱讀這些源碼極具啟發性。你可以使用repl庫的source函數來查閱某個clojure函數的源碼。

查閱一下簡單的identity函數源碼看看。

當然,你也可以使用java的反射api。用諸如class、ancestors和instance?這樣的方法,來反射其底層的java對象模型。例如,clojure的容器同樣也是java容器。

1新開啟一個repl,能防止你之前輸入的代碼,與本書示例代碼中的同名函數之間産生名字沖突。如同你将在“命名空間”中看到的那樣,在實際開發中這不會成為問題。

2 doc實際上是一個clojure的宏。