客户和利益相关者在行业标准平台(如 JVM)上投入了大量资金,并且对这些平台的性能、安全性和稳定性感到满意。虽然 Java 开发人员可能羡慕动态语言的简洁性、灵活性和生产力,但他们也担心在客户批准的基础设施上运行、访问其现有的代码库和库以及性能问题。此外,他们还面临着使用原生线程和锁处理并发的持续问题。Clojure 试图在这个背景下进行务实的动态语言设计。它力求成为一种通用语言,适用于 Java 适用的那些领域。它反映了这样一个现实,即对于并发的未来,普遍的、不受控制的变异必须停止。
Clojure 通过以下方式实现其目标:拥抱行业标准的开放平台 - JVM;对久负盛名的语言 Lisp 进行现代化改造;使用不可变的持久数据结构来促进函数式编程;并通过软件事务内存和异步代理提供内置的并发支持。其结果是健壮、实用且快速。
Clojure 对状态和标识有独特的方法。
我为什么要编写另一种编程语言?基本上是因为我想要
一种 Lisp
用于函数式编程
与已建立的平台共生
专为并发而设计
而找不到合适的。以下是 Clojure 背后一些驱动思想的概述。
经常被模仿/剽窃,但从未被复制
λ 演算产生了极其小的核心
几乎没有语法
核心优势仍然是代码即数据和语法抽象
标准 Lisp(Common Lisp 和 Scheme)怎么样?
标准化后发展缓慢/缺乏创新
核心数据结构可变,不可扩展
规范中没有并发
JVM 已经存在良好的实现(ABCL、Kawa、SISC 等)
标准 Lisp 是它们自己的平台
Clojure 是一种不受向后兼容性约束的 Lisp
将代码即数据的范式扩展到映射和向量
默认使用不可变性
核心数据结构是可扩展的抽象
拥抱平台 (JVM)
不可变数据 + 一等函数
始终可以通过 Lisp 的纪律/约定来实现
但如果数据结构*可以*被修改,则认为它不会被修改是危险的
在传统 Lisp 中,只有列表数据结构是结构递归的
纯函数式语言倾向于强静态类型
并非所有人都适用,也并非所有任务都适用
Clojure 是一种具有动态特性的函数式语言
所有数据结构都是不可变且持久的,支持递归
异构集合,返回类型
动态多态
虚拟机,而不是操作系统,是未来的平台,提供
类型系统
动态强制和安全
库
抽象掉操作系统
庞大的功能集
内置和第三方
内存和其他资源管理
GC 是平台,而不是语言,功能
字节码 + JIT 编译
抽象掉硬件
语言即平台与语言 + 平台
旧方法 - 每种语言都定义自己的运行时
GC、字节码、类型系统、库等
新方法 (JVM、.Net)
独立于语言的通用运行时
为平台构建的语言与移植到平台的语言
许多新语言仍然采用“语言即平台”的方法
移植时,存在平台上平台的问题
内存管理、类型系统、线程问题
库重复
如果原始语言基于 C,则一些用 C 编写的扩展库不会移植过来
平台由客户决定
“必须在 JVM 上运行”或 .Net 与“必须在 Unix 上运行”或 Windows
JVM 拥有成熟的记录和信任级别
现在也是开源的
需要与其他代码互操作
如今,C 链接已不足够
Java/JVM 是语言 + 平台
这不是最初的故事,但 JVM 的其他语言一直存在,现在被 Sun 接受
Java 可能很冗长,表达能力不足
缺乏一等函数,没有类型推断等
调用/使用 Java 的能力至关重要
Clojure 是语言,JVM 是平台
诞生于模拟,现在用于所有场合,即使在不合适的情况下
由于 Java/C# 缺乏对其他任何事物的(惯用)支持,因此在所有情况下都鼓励使用它
可变的有状态对象是新的意大利面条代码
难以理解、测试和推理
并发灾难
继承不是实现多态的唯一途径
“让 100 个函数操作一个数据结构,比让 10 个函数操作 10 个数据结构更好。” - Alan J. Perlis
Clojure 将其数据结构建模为由接口表示的不可变对象,否则不提供自己的类系统。
许多函数定义在少数主要数据结构上(seq、map、vector、set)。
在 Java 中编写 Java,从 Clojure 中使用和扩展 Java。
switch 语句、结构匹配等会导致脆弱的系统
多态产生可扩展、灵活的系统
Clojure 多方法将多态与 OO 和类型解耦
支持多种分类法
通过静态、动态或外部属性、元数据等进行分派
不可变性使许多问题消失
在线程之间自由共享
但更改状态对于模拟以及程序内代理到外部世界的现实是必须的
锁定很难一遍又一遍地正确处理
Clojure 的软件事务内存和代理系统负责处理难题
简而言之,我认为 Clojure 作为一种具有强大并发支持的 JVM 函数式 Lisp 占据了一个独特的利基市场。查看一些特性或开始使用 Clojure。