英文原文:getting started with clojure,翻譯:開源中國
我將嘗試教一些人(主要是Python開發者,在OS X作業系統執行)如何使用Clojure, 因為我覺得目前已經存在的一些教人如何從零開始學習Clojure的文件不盡如人意。 當我自己在幾個月前親身經歷這一切,這是一個奇怪的時期, 好幾個星期我一直處於迷茫中, 我基本上找不到一個關於Clojure生態系統的概念路線圖,也不知道如何組織一個。
我這篇文章的目標是建立該資源(我本該六個月前就建立它)。我將假設您正使用OS X作業系統並且有些許程式設計經驗
關於 Clojure 的書籍
你首先應該購買並開始閱讀 Clojure Programming. 還有另外一本叫“Programming Clojure” (書名有點容易混淆) ,我不能保證說它更好或者更差, 但我喜歡 “Clojure Programming” 並且一直使用它,所以我推薦它。 寫這本書的人都是那些你搜尋Clojure社群時常常見到的大牛們的名字。在Clojure社群, 所有主要的人物似乎都毫無人性地多產。
讓我們開始吧
現在,讓我們開始配置你的環境。 獲取Homebrew -“OS X預設的包管理器” – 準備好後, 執行下面的命令:
1 |
brew install clojure |
這個命令將安裝一個Clojure 副本,你可以通過‘clj’ 命令進行訪問。 繼續並執行它,你會看到REPL啟動, 隨便發揮吧。 你會發現自己並不是常常用到這個副本, 但是有它總是好的,特別是當你想直接執行一個Clojure 檔案可以通過命令clj a_file.clj
進行。
你不會經常用到’clj’ 是因為REPL預設的原始的Clojure環境非常的垃圾。它不支援使用向上箭頭訪問之前計算的表示式; 它不支援使用’C-a’ 和’C-e’到達每一行的開始/末尾;這真的非常氣人, 你會討厭它的, 因此別使用它。
你下一個步驟是安裝Leiningen, 從現在開始你幾乎會從不間斷地用到它。通常, 你需要安裝 Leiningen 2, 雖然它目前還不是Leiningen的公開的發行版本,但相信我它就是你要安裝的版本。你可以通過執行下面的命令得到它:
1 |
brew install leiningen --devel |
這個 –devel 標記, 告訴Homebrew 我們需要的是 Leiningen 2 而不是 Leiningen 1.x. 我花了不少時間才搞懂它。
那麼Leiningen究竟是什麼鬼東西?
Leiningen是你的主要工具, 它用於:
- 啟動一個 REPL
- 下載+安裝類庫
- 執行你的程式
- 啟動一個伺服器, 執行你所寫的webapps
接著執行 lein repl
. 它會啟動一個真正有用的 REPL, 任何時候,當你需要一個REPL,用這個命令就行。 使用向上方向鍵你會得到之前用過的計算表示式, 而快捷鍵 C-a 和 C-e 也能生效(到達行首/行尾), 一切都像你所期望的那樣。另外,如果你在頂級目錄執行一個Clojure 專案,它會根據實際情況處理連線類路徑和諸如此類的東西,這樣你就可以匯入和玩玩你專案的程式碼和庫了。 稍後我們再討論這個。現在,讓我們通過下面的命令建立一個骨架專案玩玩:
1 |
lein new foo |
命令完成後, cd 到 foo 目錄,你會看到它已經有了一些檔案和目錄:
1 2 3 4 5 6 7 |
[jrheard@jrheard-air:~/dev/foo] $ ll total 16 -rw-r--r-- 1 jrheard staff 193B Jan 5 15:17 README.md drwxr-xr-x 3 jrheard staff 102B Jan 5 15:17 doc -rw-r--r-- 1 jrheard staff 263B Jan 5 15:17 project.clj drwxr-xr-x 3 jrheard staff 102B Jan 5 15:17 src drwxr-xr-x 3 jrheard staff 102B Jan 5 15:17 test |
當你寫一個Clojure 庫/程式/或者任何東西,你的原始碼都儲存在“src”目錄,你的測試程式碼則儲存在“test”目錄。非常簡單。 讓我們來看看 src 目錄:
1 |
[jrheard@jrheard-air:~/dev/foo] $ cat src/foo/core.clj |
1 |
(ns foo.core) (defn foo "I don't do a whole lot." [x] (println x "Hello, World!")) |
看起來 Leiningen 已經建立了一個叫 “src/foo/core.clj” 的檔案。這是一個Clojure程式, 它定義了一個“foo.core”的名稱空間, 然後宣告該名稱空間包含一個名為“foo”的函式。 我們來看看它。用lein repl
啟動一個REPL 並瀏覽一下。 還記得我前面提到過Leiningen會負責處理你的類路徑和相關的goop,這樣你就可以從REPL訪問你的專案程式碼了? 看看這個:
1 2 3 4 |
user=> (use 'foo.core) nil user=> foo #<core$foo foo.core$foo@6ad591a6> user=> (foo "jrheard") jrheard Hello, World! nil |
真棒 – 我們已經能夠匯入我們的程式碼並執行它。 use
提供了類似於Python裡面的from foo.core import *
相同 的功能,因此不鼓勵在原始碼中再使用它( from foo.core import *), 出於相同的原因, import *也不再鼓勵使用。不過像 import * ( 這樣的功能), 在你查詢(瀏覽)REPL 的時候是相當有用的。
嘿,非常酷 – 我們已經建立了一個專案, 裡面還生成一些程式碼, 我們已經知道如何啟動一個能執行的REPL 還可以在裡面瀏覽那些程式碼。 第一階段已經完成啦, 讓我們來看看第二個階段:
下裝並安裝類庫
你可能習慣在命令列執行一些命令來獲取類庫。例如 pip install this_great_library_i_found
, 它會下載你指定的類庫, 並安裝到全域性的或者你當前的虛擬環境中(virtualenv)。 但是在 Clojure 裡, 有一點點不一樣。
首先,你必須找到一個看起來還不錯的類庫。 Clojure Toolbox 是一個奇妙的工具,這是我發現的最好的資源。 我們選擇一個庫玩玩: 建立HTTP請求很有意思 – 讓我們先到 “HTTP Clients” 的章節, 看看我們都有哪些選擇。 看起來我們得在 clj-http 和 http.async.client 之間挑一個 -但是選哪一個呢?
目前,在多個存在競爭關係的類庫之間做選擇時,我最喜歡的方式是:把它們從github倉庫里拉下來,然後比較加星數和fork數之和,如果最近兩個月有提交程式碼可以加分,用這個數代表社群的健壯性、影響力或適應能力,可能不是特別科學,不過我用著挺好的。在寫這篇文章的時候,clj-http有242個星號,http.async.client只有127個,所以我選擇clj-http。
所以… 怎麼搞到它?
讓我們開啟 clj-http’s github repo。README中關於安裝那一段有如下程式碼:
1 |
[clj-http "0.6.3"] |
這就是我們需要的資訊 – 這是一個 Clojure vector,它包含兩個條目,第一個條目是類庫的名字, 第二個條目標識最新的穩定版本。我們打算把它新增到我們的(你之前在檢視’foo’ 目錄的內容看到的那一個) project.clj. 開啟 project.clj, 看起來就像這樣:
1 2 3 4 5 6 |
(defproject foo "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.4.0"]]) |
注意:dependencies 那段 – 這是一個包含一個條目的Clojure vector, 該條目本身也是一個包含兩個條目的的 Clojure vector. 這個 vector 告訴 Leiningen 我們的專案要執行在版本是1.4.0的Clojure 上.夠公平的了,現在讓我們新增我們之前看到的那個clj-http vector。 現在 project.clj 看起來應該像這樣:
1 2 3 4 5 6 7 |
(defproject foo "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.4.0"] [clj-http "0.6.3"]]) |
就是這樣!現在我們已經指定了我們需要的clj-http類庫和版本號。讓我們試一下 -使用lein repl
命令啟動一個REPL,來測試我們精選的新類庫。要注意的是,在REPL啟動的時候Leiningen會首先下載clj-http,這是因為基本上在我們的所有操作之前,它會先在後臺執行lein deps
命令掃描 project.clj檔案,並且確保已經獲取到了所有我們需要的依賴類庫。
好的,回到我們的REPL會話,這裡有一個從clj-http的github上返回的README,它告訴我們需要在REPL上執行
1 |
(require ‘[clj-http.client :as client]) |
好吧我們執行一下,-這跟Python中’from clj.http import client’是一樣的(與from clj.http.client import *
截然相反,這也是’use’函式的工作)
1 2 |
user=> (require '[clj-http.client :as client]) nil user=> (client/get "http://www.yelp.com") ;; a big huge blob of data pops out! |
哇,好了,看到它能執行了!那些排列讀起來很糟糕——你會發現以”}”結束的超大塊的資料,那大概是Clojure map型別的小許資料。接下來試試下面的程式碼:
1 2 3 4 5 6 7 8 9 |
user=> (def resp (client/get "http://www.yelp.com")) #'user/resp user=> (type resp) clojure.lang.PersistentArrayMap user=> (keys resp) (:cookies :trace-redirects :request-time :status :headers :body) user=> (:status resp) 200 user=> (:headers resp) {"server" "Apache", "content-encoding" "gzip", "x-proxied" "lb2", "content-type" "text/html; charset=UTF-8", "date" "Sun, 06 Jan 2013 00:02:58 GMT", "cache-control" "private", "vary" "Accept-Encoding,User-Agent", "transfer-encoding" "chunked", "x-node" "wsgi, web40, www_all", "x-mode" "ro", "connection" "close"} |
執行之後,我們發現了一個HTTP客戶端庫,下載它,並且指出怎樣在REPL中互動使用。
把它們都找出會花掉我一些時間——在用頭撞了一天牆之後,我終於不得不來到#clojure IRC 頻道請示幫助。現在你不用那樣做了!想進一步閱讀的,請看 the official Leiningen tutorial。
把它們全部放一起
讓我們通過弄清如何實際執行一個Clojure程式來完成。我們嘗試一個典型的lein run
:
1 2 |
[jrheard@jrheard-air:~/dev/foo] $ lein run No :main namespace specified in project.clj. |
好的,這沒成功執行。返回之前提到過的Leiningen手冊然後搜尋下:main,我們看到你可以第一個一個:main關鍵字在你的project.clj定義裡來指定lein run
會執行的名稱空間,也就是說這個名稱空間必需包含一個-main
的函式來為你的程式提供入口點。讓我們把這行程式碼加入到我們的project.clj定義裡:
1 |
:main foo.core |
最後我們修改src/foo/core.clj,然後它的程式碼如下:
1 2 3 4 5 6 7 8 9 |
(ns foo.core (:require [clj-http.client :as client])) (defn -main "Prints the first 50 characters of the HTML source of yelp.com." [& args] (println (apply str (take 50 (:body (client/get "http://www.yelp.com")))))) |
到這裡,我們繼續嘗試lein run
:
1 2 3 4 |
[jrheard@jrheard-air:~/dev/foo] $ lein run Compiling foo.core <!DOCTYPE HTML> <!--[if lt IE 7 ]> <html xmlns:fb |
它成功了!
目前來說-你現在有了一個可執行的REPL來玩耍,安裝和使用庫的能力,讓你的程式訪問這些庫以及執行的知識,還有一本真正能給你一切你所需知道的關於Clojure語言的好書。
我為何必須寫這篇文章
Clojure還是一門非常年輕的語言。跟Python比的話,它的社群也還特別小。儘管我說過它的核心API非常穩定,但很多周邊工具都是新的而且還在快速變化。最重要的是你會發現很多最新的文件都沒有做好SEO,大部分的Google搜尋結果都會轉到richhickey.github.com,而它上面的很多東西都過時了。所以你會覺得Clojure很難上手。
希望本文能讓你少迷茫幾個星期,避免重蹈我的覆轍。我保證成長的痛苦是值得的,Clojure會讓你享受到程式設計的真正樂趣。
各種資源
- 看看 Rich Hickey(clojure 的創始人)的兩個演講 : “Are We There Yet?” 和“Simple Made Easy”. 特別注意的是,過幾個月看下第一個演講三到四次。
- 我花了過去的幾個星期看了所有有關clojure的演講。官方youtube頻道不錯 official Clojure youtube channel , InfoQ也有很多不錯的內容( great content on InfoQ ),我在這最少看了25個演講。
- The Clojure Toolbox, 尋找現成的庫
- Where Did Clojure.Contrib Go – 你要檢視一些庫的手冊,比如“clojure.contrib.monads, 正像你看到的, clojure.contrib 這個庫不會存在多久, 這個頁面會告訴你 庫被合併到哪去了。
- This example project.clj 展示了很多Leiningen提供的鉤子(hooks)不同的高階用法,輕鬆定製,構建你的專案
- 你可以在twitter上 following clojure 社團的核心成員 @cgrand, @cemerick, @marick, @weavejester, @stuartsierra, @seancorfield, @Baranonsky, @richhickey
- 讀 “The Joy of Clojure” 如果你已經看完了 “Clojure Programming”.
- 特別注意,Noir已經不維護了,使用Compojure代替吧