Clojure

title: 历史与开发过程.
content: 里奇·希基(Rich Hickey)是Clojure语言的创造者。 在Clojure之前,他开发过类似但基于.NET平台的项目——dotLisp。 在那之前,他还有过三次旨在在Lisp与Java之间提供互操作(interoperability)的尝试:“Common Lisp的Java外语接口”[Java foreign language interface for Common Lisp (jfli)]、“Lisp的外语对象接口”[Foreign Object Interface for Lisp (FOIL)]以及“Lisp友好的Java Servlet接口”[Lisp-friendly interface to Java Servlets (Lisplets)]。  在公开发布之前,里奇·希基在Clojure的工作上花了大约两年半的时间。期间,在没有外部资金的情况下,他将其大部分时间都专门投入到了Clojure的工作上。在这段时间结束时,里奇·希基以电子邮件的形式向他在Common Lisp社区里的一些朋友宣布了该语言。  Clojure的开发过程由社区驱动并且在Clojure JIRA项目网页上进行管理。 该网站可用于提交问题报告(issue)。一般的开发讨论是在“Clojure谷歌网上论坛”(Clojure Google Group)上进行的。 任何人都可以提交错误报告和想法,而贡献补丁(patches)则需要先签署“Clojure贡献者协议”(Clojure Contributor Agreement)。 JIRA错误报告(JIRA ticket)由一个筛选者(screener)团队进行处理并最终由里奇·希基批准更改。
title: 设计理念.
content: 里奇·希基开发Clojure的原因是因为他想要一款适合函数式编程的现代Lisp。该语言既需要与已建立的Java平台共生又需要有适合并发性的设计。  Clojure对待变化(change)的方式以标识(identity)的概念为特征。 标识是指随着时间的推移而产生的一系列状态(state)。而状态则是指标识在某一特定时间点上的值(value)。需要强调的是,这里的值是不可变的(immutable)。由此引申,由于状态是不可变的值,任意数量的工作单位(workers)都可以在其上以并行(parallel)的方式实施操作。因此,并发性(concurrency)就成为一道管理状态间变化的问题[注意,这里的“变化”是指从一个状态到另外一个状态的跃迁(transition)而不是状态本身的变化(mutation)。]为此,Clojure提供了几个可变的(mutable)引用类型(reference type)。每个引用类型都有其明确定义的语义用于控制状态之间的跃迁。
title: 语言概述.
content: Clojure执行于Java平台之上,因此,与Java紧密集成并完全支持从Clojure调用Java代码。<ref name="about/jvm_hosted"></ref> 与此同时,也可以从Java调用Clojure代码。 Leiningen是社区中普遍使用的项目自动化工具。Leiningen为Maven集成提供支持,处理项目包管理和依赖项。Leiningen的配置使用的则是Clojure语法。  与其他大多数Lisp一样,Clojure的语法建立在S-表达式之上。S-表达式在被编译之前先由读取器(reader)解析为数据结构。<ref name="reference/reader"></ref> 除了列表(list)之外,Clojure的读取器还支持映射(map)、集合(set)及向量(vector)等的字面量(literal)语法。这些字面量随后会被直接编译成上述数据结构。 Clojure是Lisp-1且有一套与其它Lisp不兼容的数据结构,因此,Clojure不支持与Lisp的其它方言之间的代码级兼容性。  作为一门Lisp方言,函数在Clojure中是一等公民。此外,Clojure还支持读取-求值-输出循环(REPL)以及一套宏系统。 Clojure的Lisp宏系统与Common Lisp的系统极为相似。唯一不同的是,Clojure的重音符[称为“语法引用”(syntax quote)]用名字空间(namespace)来限定符号(symbol)。这有助于防止意外的名字捕获(unintended name capture),因为Clojure禁止绑定(binding)到用名字空间限定的名字(namespace-qualified name)上。如果需要强制捕获宏扩展(capturing macro expansion,)那么就需要显示地完成该过程。Clojure不支持用户定义的读取器宏(reader macro,)但Clojure的读取器支持更具约束力的语法扩展(syntactic expansion)形式。 Clojure支持多重方法(multimethods。) 对于类似接口的抽象,Clojure提供基于协议(protocol)的多态性(polymorphism)以及基于记录(record)的数据类型系统。 Clojure通过这些设计来提供高性能且动态的多态性以避免所谓的“表达式问题”("expression problem"。)  Clojure支持惰性序列,并鼓励不可变性(immutability)与持久数据结构(persistent data structure。)Clojure作为一门函数式编程语言将重点放在递归与高阶函数上而不是基于副作用的循环流程上。Clojure不支持自动尾调用优化,因为JVM还不支持该项优化,但是,可以用codice_1关键字显式地进行该项优化。 对于并行与并发计算,Clojure提供软件事务内存、 响应式代理系统及基于通道(channel)的并发编程。  Clojure 1.7引入了读取器条件表达式(reader conditional)从而允许在同一名字空间中嵌入Clojure与ClojureScript代码。 变换归纳器(transducer)的加入则提供了另一种组合变换的方法。变换归纳器可以使高阶函数(如,codice_2和codice_3)更加抽象从而使之独立于其输入数据源。传统地说,这些函数一般被应用于序列(sequence)上,而变换归纳器允许这些函数被应用于通道(channel)上并让用户定义她们自己的变换归纳(transduction)模型。
title: 平台.
content: 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。
title: 人气.
content: 随着对函数式编程的兴趣的持续升温,Clojure也越来越多地受到Java平台上的软件开发人员的青睐。该语言也一度成为知名软件开发老将(如Eric Evans 、詹姆斯·高斯林、保罗·格雷厄姆及Robert C. Martin(俗称“Uncle Bob”)等)的首选或推荐语言。  在由Snyk和Java Magazine合作编写的“JVM生态系统报告2018”(据称是“Java开发人员有史以来规模最大的调查”)中,Clojure被评为用于“主要应用程序”的第二大人气编程语言(仅次于Java)。  业内使用Clojure的公司有苹果公司、Atlassian、Funding Circle、Netflix、 Puppet、沃尔玛及其他大型软件公司与美国国家航空航天局等政府机构。Clojure也一度被用于创意计算,包括视觉艺术、音乐、游戏和诗歌。  美国知名软件咨询公司ThoughtWorks在为其“技术雷达”评估函数式编程语言时表达了他们对Clojure的青睐,称其为“Lisp在JVM上的简单及优雅实现”,并在2012年将其状态提升为“采用”(“ADOPT”)。  越来越多的非官方和/或实验性的其他平台实现也验证了该语言的人气:
title: 开发工具.
content: Clojure的开发工具在近几年得到了显著的改善。以下是目前最具人气的集成开发环境(IDE)/编辑器及其Clojure插件。这些工具的结合为Clojure编程提供了出色的支持。 除了社区提供的开发工具之外,官方的命令行界面(CLI)工具<ref name="guides/deps_and_cli"></ref>也随着Clojure 1.9一起发布并可在GNU/Linux、macOS及Windows上使用。
title: 功能示例.
content: 以下示例均可在Clojure REPL中运行(如,使用Clojure命令行界面工具启动的REPL或在REPL.it上提供的在线REPL。)
title: 简单性.
content: 由于强调简单性,典型的Clojure程序主要包括函数和简单的数据结构(即列表,向量,映射和集合):
title: REPL编程.
content: 与其他Lisp一样,Clojure的标志性特征之一是基于REPL的交互式编程。在以下示例中,codice_4表示一行注释的开始,而codice_5则表示输出:
title: 运行时可用的名字.
content: 与Clojure不同,其他语言的编译器会将程序中的名字编译掉使得它们在运行时不可用。而在Clojure中,可以用普通的数据结构对其运行时进行观察:
title: 代码即数据(同像性).
content: 与其他Lisp类似,Clojure也具有同像性[又被称为“代码即数据”(code as data)]。从下面的示例中可以看到,用Clojure编写代码从而修改代码本身是非常容易的:
title: 富有表现力的数据变换操作符.
content: 穿梭宏(threading macro,如,codice_6、codice_7等)可以在语法上表达一个数据集在一系列变换间穿梭的抽象:  利用变换归纳器(transducer)也可以更有效地实现该过程:
title: 标识及其状态的线程安全管理.
content: 线程安全的唯一序列号生成器(然而,和许多其他Lisp方言一样,Clojure内部使用其内置的codice_8函数):
title: 宏.
content: codice_9的一个匿名子类(不写任何内容)和一个宏(使用该类来静音其中打印的所有内容):
title: Java互操作.
content: 作为其主要设计目标之一,Clojure从一开始就将其宿主平台(host platforms)视为其不可分割的一部分。Clojure与Java之间出色的互操作即得益于此:
title: 软件事务内存.
content: 10个线程操纵一个共享数据结构,该结构由100个向量组成,而每个向量包含10个(最初是连续的)唯一数字。每个线程随后在两个随机向量中重复选择两个随机位置并交换它们。通过使用Clojure的软件事务内存系统,对向量的所有更改都发生在事务中:

Summary: Clojure()<ref name="interview/a-z">是Lisp编程语言在Java平台上的现代、动态及函数式方言。<ref name="platform/android"> 与其他Lisp一样,Clojure视代码为数据且拥有一套Lisp宏系统。<ref name="reference/lisps"> 其开发过程目前由社区驱动,<ref name="dev/dev"> 其作者里奇·希基(Rich Hickey)则以终身仁慈独裁者(BDFL)的身份进行监督。