Clojure

**Clojure**（/ˈkloʊʒər/）是 Lisp 程式語言在 Java 平台上的現代、動態及函數式方言。 與其他 Lisp 一樣，Clojure 視代碼為資料且擁有一套 Lisp 巨集系統。Clojure 的開發過程目前由社群驅動，其作者里奇・希基則以終身仁慈獨裁者的身分監督。

Clojure 提倡不可變性與持久資料結構並鼓勵程式設計師顯式地管理標識及其狀態。對利用不可變值及顯式時間進展構造（explicit progression-of-time constructs）進行編程的專注旨在促進更加健壯的（尤其是並行）程式的開發。Clojure 的型別系統是完全動態的，但人們近期也開始探索其基於漸進類型化的實現。

對 Clojure 的商業支援由 Cognitect 公司提供。 每年都會在全球範圍內舉辦年度 Clojure 會議，其中最著名的是 Clojure/conj。

## 歷史與開發過程

里奇・希基創造了 Clojure 語言。此前，他開發過類似但基於.NET 平台的專案 ——dotLisp。在那之前，他還嘗試了三次在 Lisp 與 Java 之間提供互操作：Common Lisp 的 Java 外語介面、Lisp 的外語物件介面以及 Lisp 友好的 Java Servlet 介面。

在公開發布之前，里奇・希基花了大約兩年半的時間開發 Clojure。他在沒有外部資金的情況下，將其大部分時間都專門投入到了 Clojure 的工作上。開發快要完成，里奇・希基向 Common Lisp 社群里的一些朋友發布電子郵件，宣布他完成開發了 Clojure。

Clojure 的開發過程在 Clojure JIRA 專案網頁由社群驅動並管理。該網站可用於提交問題報告。一般的開發討論是在 ClojureGoogle 網上論壇上進行的。 任何人都可以提交錯誤報告和想法，而貢獻修補程式前則需要先簽署 Clojure 貢獻者協定。 JIRA 錯誤報告由一組篩選者處理，最終由里奇・希基批准更改。

## 設計理念

里奇・希基開發 Clojure 的原因是因為他想要一款適合函式語言程式設計的現代 Lisp。該語言既需要與已建立的 Java 平台共生又需要有適合並行性的設計。

在 Clojure 中，狀態以標識的概念為特徵。一系列狀態隨著時間的推移而產生，就是標識。由於狀態是不可變的值，任意數量的工作單位都可以在其上並列實施操作，並行性就成為一道管理狀態到狀態的變化的問題。因此，Clojure 提供了幾個可變的參照類型。每個參照類型都有其明確定義的語意用於控制狀態之間的躍遷。

## 語言概述

Clojure 執行於 Java 平台之上，因此，與 Java 緊密整合並完全支援從 Clojure 呼叫 Java 代碼。 與此同時，也可以從 Java 呼叫 Clojure 代碼。 Leiningen 是社群中普遍使用的專案自動化工具。Leiningen 為 Maven 整合提供支援，處理專案包管理和依賴項。Leiningen 的組態使用的則是 Clojure 語法。

與其他大多數 Lisp 一樣，Clojure 的語法建立在 S - 表達式之上。S - 表達式在被編譯之前先由讀取器解析為資料結構。 除了列表之外，Clojure 的讀取器還支援對映、集合及向量等的字面量語法。這些字面量隨後會被直接編譯成上述資料結構。 Clojure 是 Lisp-1 且有一套與其它 Lisp 不相容的資料結構，因此，Clojure 不支援與 Lisp 的其它方言之間的代碼級相容性。

作為一門 Lisp 方言，函式在 Clojure 中是一等公民。此外，Clojure 還支援讀取﹣求值﹣輸出迴圈以及一套巨集系統。 Clojure 的 Lisp 巨集系統與 Common Lisp 的系統極為相似。唯一不同的是，Clojure 的重音符（稱為語法參照）用命名空間來限定符號。這有助於防止意外的名字擷取，因為 Clojure 禁止繫結到用命名空間限定的名字（namespace-qualified name）上。如果需要強制擷取巨集擴充（capturing macro expansion，）那麼就需要顯示地完成該過程。Clojure 不支援使用者定義的讀取器巨集（reader macro，）但 Clojure 的讀取器支援更具約束力的語法擴充形式。 Clojure 支援多方法（multimethods。） 對於類似介面的抽象，Clojure 提供基於協定的多型性以及基於記錄的資料類型系統。 Clojure 通過這些設計來提供高效能且動態的多型性以避免所謂的「表達式問題」（"expression problem"。）

Clojure 支援惰性序列，並鼓勵不可變性與持久資料結構（persistent data structure。）Clojure 作為一門函式語言程式設計語言將重點放在遞迴與高階函式上而不是基於副作用的迴圈流程上。Clojure 不支援自動尾呼叫最佳化，因為 JVM 還不支援該項最佳化，但是，可以用 `recur` 關鍵字顯式地執行該項最佳化。 對於並列與並行計算，Clojure 提供軟體事務記憶體、 回應式代理系統及基於通道的並行編程。

Clojure 1.7 引入了讀取器條件表達式從而允許在同一命名空間中嵌入 Clojure 與 ClojureScript 代碼。 變換歸納器的加入則提供了另一種組合變換的方法。變換歸納器可以使高階函式（如，`map` 和 `fold`）更加抽象從而使之獨立於其輸入資料來源。傳統地說，這些函式一般被應用於序列上，而變換歸納器允許這些函式被應用於通道上並讓使用者定義她們自己的變換歸納模型。

## 平台

Clojure 的主要平台是 Java 但也存在其他目標平台上的實現。其中，最值得關注的是 ClojureScript（可被編譯成 ECMAScript 3）和 ClojureCLR（.NET 平台上的完整移植版，可與其生態系統互操作。）2013 年對 1,060 名受訪者進行的 Clojure 社群調查發現，47％的受訪者在使用 Clojure 的同時也使用 ClojureScript。2014 年，這一數字增長到了 55％，而到了 2015 年，則達到了 66％（根據 2,445 名受訪者）。 人氣較高的 ClojureScript 專案包括 React 實現，如 Reagent、re-frame、Rum 及 Om。

## 人氣

隨著對函式語言程式設計的興趣的持續升溫，Clojure 也越來越多地受到 Java 平台上的軟體開發人員的青睞。該語言也一度成為知名軟體開發老將的首選或推薦語言，如 Brian Goetz、Eric Evans、詹姆斯・高斯林、保羅・格雷厄姆及 Robert C. Martin（俗稱「鮑勃大叔」）等人。

在由 Snyk 和 Java Magazine 合作編寫的「JVM 生態系統報告 2018」（據稱是「Java 開發人員有史以來規模最大的調查」）中，Clojure 被評為用於「主要應用程式」的第二大人氣程式語言（僅次於 Java）。

業內使用 Clojure 的公司有蘋果公司、Atlassian、Funding Circle、Netflix、 Puppet 、沃爾瑪及其他大型軟體公司與美國國家航空暨太空總署等政府機構。Clojure 也一度被用於創意計算，包括視覺藝術、音樂、遊戲和詩歌。

美國知名軟體諮詢公司 ThoughtWorks 在為其「技術雷達」評估函式語言程式設計語言時表達了他們對 Clojure 的青睞，稱其為「Lisp 在 JVM 上的簡單及優雅實現」，並在 2012 年將其狀態提升為「採用」（「ADOPT」）。

越來越多的非官方和 / 或實驗性的其他平台實現也驗證了該語言的人氣：

* CljPerl：Clojure 的 Perl 實現
* Clojerl：BEAM（Erlang 虛擬機器）上的 Clojure
* clojure-py：Clojure 的純 Python 實現
* Ferret：可被編譯成執行於微控制器的自包含（self-contained）C++11
* Joker：用 Go 實現的直譯器和 linter
* Las3r：執行於 ActionScript 虛擬機器（Adobe Flash Player 平台）的 Clojure 子集
* Pixie：受 Clojure 啟發並用 RPython 實現的 Lisp 方言
* Rouge：Clojure 基於 YARV 的 Ruby 實現

## 開發工具

Clojure 的開發工具在近幾年得到了顯著的改善。以下是目前最具人氣的整合式開發環境 / 編輯器及其 Clojure 外掛程式。這些工具的結合為 Clojure 編程提供了出色的支援。

除了社群提供的開發工具之外，官方的命令列介面工具也隨著 Clojure 1.9 一起發布並可在 GNU/Linux、macOS 及 Windows 上使用。

## 功能範例

以下範例均可在 Clojure REPL 中執行（如，使用 Clojure 命令列介面工具啟動的 REPL 或在 REPL.it 上提供的線上 REPL。）

### 簡單性

由於強調簡單性，典型的 Clojure 程式主要包括函式和簡單的資料結構（即列表，向量，對映和集合）：

### REPL 編程

與其他 Lisp 一樣，Clojure 的標誌性特徵之一是基於 REPL 的互動式編程。在以下範例中，`;;` 表示一行注釋的開始，而 `;; =>` 則表示輸出：

### 執行時可用的名字

與 Clojure 不同，其他語言的編譯器會將程式中的名字編譯掉使得它們在執行時不可用。而在 Clojure 中，可以用普通的資料結構對其執行時進行觀察：

### 代碼即資料（同像性）

與其他 Lisp 類似，Clojure 也具有同像性（又稱代碼即資料）。從下面的範例中可以看到，用 Clojure 編寫代碼從而修改代碼本身是非常容易的：

### 富有表現力的資料變換運算子

穿梭巨集（threading macro，如，`->`、`->>` 等）可以在語法上表達一個資料集在一系列變換間穿梭的抽象：

利用變換歸納器也可以更有效地實現該過程：

### 標識及其狀態的執行緒安全管理

執行緒安全的唯一序列號生成器（然而，和許多其他 Lisp 方言一樣，Clojure 內部使用其內建的 `gensym` 函式）：

### 巨集

`java.io.Writer` 的一個匿名子類（不寫任何內容）和一個巨集（使用該類來靜音其中列印的所有內容）:

### Java 互操作

作為其主要設計目標之一，Clojure 從一開始就將其宿主平台視為其不可分割的一部分。Clojure 與 Java 之間出色的互操作即得益於此：

### 軟體事務記憶體

10 個執行緒操縱一個共享資料結構，該結構由 100 個向量組成，而每個向量包含 10 個（最初是連續的）唯一數字。每個執行緒隨後在兩個隨機向量中重複選擇兩個隨機位置並交換它們。通過使用 Clojure 的軟體事務記憶體系統，對向量的所有更改都發生在事務中：

## 參考文獻

## 延伸閱讀

## 外部連結

官方網站