Clojure的基本理念

Clojure的基本理念

原文地址 客户和相关人员都对诸如JVM这样的行业标准平台的性能、安全性以及稳定性进行了大量投资,并且对其感到满意。虽然Java开发者可能会对动态语言的简洁、灵活性及生产力感到嫉妒,但是他们要考虑在客户允许的基础结构上运行、访问已有的代码库以及性能等方面的问题。除此之外,他们还要面对使用原生线程和加锁处理并发时所持续不断出现的问题。Clojure就是在这样一种背景下所做出的实用动态语言设计的努力。它致力于成为一种Java所适用的那些领域中的通用语言。它反映出这样一个现实,对于将来的并发编程来说,现在普遍存在的、不受约束的状态变化必然会消失。

Clojure通过以下几点来达到它的目的:

  • 拥抱行业标准的开放平台——JVM
  • 对一门值得尊敬的语言——Lisp进行现代化改造
  • 通过不变的持久化数据结构来促进函数式编程
  • 通过软件事务内存和异步代理提供内建的并发支持

我们最终得到的是一门健壮、实用而快速的语言。

Clojure对于状态和同一性采取了一种与众不同的方式。

为什么会有Clojure?

我为什么还要再编写一门程序语言?大体而言,因为我想要:

  • 一种Lisp
  • 函数式编程
  • 与已稳固建立的平台共生
  • 为并发而设计

但是我却没有找到这样一种语言。下面是对Clojure背后的一些动机的概述:

Lisp是个好东西

  • 经常被模仿/洗劫,但是仍未被复制
  • Lambda演算产生出一个非常小的核心
  • 几乎没有语法
  • 核心优势仍然是代码即数据以及语法抽象
  • 标准的Lisp(Common Lisp和Scheme)的状况
    • 标准化之后缓慢/没有革新
    • 核心的数据结构是可变的,并且不可扩展
    • 规范中没有涉及到并发
    • JVM上已经有了良好的实现(ABCL,Kawa,SISC等)
    • 标准的Lisp自身即是一个平台
  • Clojure是一种没有向后兼容性约束的Lisp
    • 将“代码即数据”的范式推广到了map和vector
    • 默认数据是不可改变的
    • 核心的数据结构是可扩展的抽象
    • 拥抱平台(JVM)

函数式编程是个好东西

  • 数据不可变+函数为一等“公民”
  • 总是能够根据行规/惯例用Lisp完成
    • 但是如果数据结构是可变的,那么假设数据不会被改变是很危险的事情
    • 在传统的Lisp中,只有list数据结构在结构上才是可递归的
  • 纯粹的函数式语言总是倾向于强静态类型
    • 并非对每个人、每个任务都合适
  • Clojure是一种强调动态性的函数式语言
    • 所有的数据都不可变&可持久化,且支持递归
    • 不同类型的集合、返回类型
    • 动态的多态

语言和平台

  • 虚拟机,而不是操作系统,才是未来的平台,它提供了:
    • 类型系统
      • 动态执行和安全性
      • 抽象了OS
      • 大量的工具
      • 内建和第三方
    • 内存及其它资源管理
      • GC是一个平台,而不是语言、工具
    • 字节码+JIT编译
      • 硬件抽象
  • 语言即平台 vs 语言+平台
    • 老的方式——每种语言定义自己的运行时
      • GC、字节码、类型系统、库等
    • 新的方式(JVM,.NET)
      • 独立于语言的通用运行时
  • 为平台构建的语言 vs 移植到平台的语言
    • 许多新的语言仍然采用“语言即平台”的方式
    • 移植时存在着平台到平台的问题
      • 内存管理、类型系统、线程问题
      • 重复的库
      • 如果原来的语言基于C的话,一些用C写的扩展库并未移植过来
  • 平台是由客户指定的
    • 必须运行在JVM或.NET上 vs 必须运行在Unix或Windows上
    • JVM已经建立了追踪记录和信任级别
      • 现在也已经开源了
    • 需要和其它代码交互
      • 现在光有C的连接是不够的
  • Java/JVM是语言+平台
    • JVM
    • Java单调乏味,表达力也不够
      • 函数不是一等公民,缺乏类型推断等
    • 调用/使用Java的能力至关重要
  • Clojure是语言,JVM是平台

OO被高估了

  • 起源于模仿,如今用在每个地方,即使并不合适也在用
    • 由于Java/C#缺乏对其它功能的(惯用的)支持,因此OO受到了它们的鼓励
  • 状态可变的对象成了新的意大利面条式代码
    • 难于理解、测试和推理
    • 并发灾难
  • 继承不是实现多态的唯一方式
  • “让100个函数操作一个数据结构要比让10个函数操作10个数据结构好“——Alan J. Perlis
  • Clojure将数据结构建模为由接口表示的不可变对象,不另外提供自己的类系统
  • 在少数几个主要数据结构(seq、map、vector和set)上定义了许多函数
  • 使用Java编写Java,从Clojure使用和扩展Java

多态是个好东西

  • Switch语句、结构匹配等导致脆弱的系统
  • 多态可以带来灵活的、可扩展的系统
  • Clojure的多方法机制将多态与OO和类型分离开来
    • 支持多种分类方法
    • 通过静态、动态、外部属性、元数据等方式进行派发

并发及多核未来

  • 不变性让许多问题都消失了
    • 在线程间自由共享
  • 对于模拟和程序与外部世界之间的代理来说,状态改变是一个现实
  • 上锁(locking)非常困难,不可能每次都能正确实现
  • Clojure的软件事务内存(software transaction memory)和代理系统(agent system)解决了困难的地方

简而言之,我认为Clojure作为JVM上一种对并发有很强支持的、能够实际运行的Lisp占据了一个独特的位置。看看Clojure的一些特点或者开始使用Clojure