Skip to main content
 首页 » 操作系统 » linux系统

Clojure启航

Clojure:

● 是一种函数式语言。

● 是一种为Java虚拟机设计的Lisp。

● 具备处理并发问题的特殊能力。

Clojure思想的核心:简单、强大。

简单:简单,就是不复杂。采用简单的组件,能让系统的设计者专注于手边的任务,从而免受各种无关杂事的打扰。无关复杂性很快就会演变为危险复杂性。

强大是否足以完成将要承担的任务,需要在一个功能丰富,且得到广泛部署的基础(例如Java虚拟机)之上构建应用。然后,使用的工具必须能完全不受限制地访问这个平台。

为什么是Clojure所有Clojure的特色功能,要么简单,要么强大,或两者兼而有之。

● 函数式编程很简单,原因是它将计算的过程与状态及标识隔离开来。

优点:函数式程序更容易理解、编写、测试、调优和并行化。

● Clojure与Java的互操作极为强大,允许直接访问Java平台的语义。

优点:能拥有与Java等同的性能和语义。最重要的是,不必为了获得这点额外的能力而“下降”到一门低级别的语言。

● Lisp的简单在于两个关键方面:它将代码的读取与求值分开了,并且语法仅由少数几个正交的部分构成。

优点:能用语法抽象来捕获设计模式;此外,当需要的时候,S表达式(S-expressions)能成为XML、JSON或是SQL。

● Lisp也很强大,它在运行期提供了一个编译器和宏(macro)系统。

优点:Lisp具有晚绑定的决策能力,并且很容易定制领域特定语言(DSL,Domain SpecificLanguage)。

● Clojure 的时间模型很简单,将值、标识、状态和时间相互分离。

优点:程序可以放心地感知并记住信息。

● 协议(Protocols)很简单,将多态性(polymorphism)和派生(derivation)分离。

优点:不必纠结于设计模式,或是依赖于脆弱的猴子补丁(monkeypatching),就能得到既安全又极富扩展性的类型与抽象。

Clojure非常优雅Clojure高信号,低噪音。因此,Clojure程序都非常简短。短小的程序,无论是构建、部署,还是维护,都要便宜得多。

Clojure启航  Clojure 第1张

isBlank()方法用于检查目标字符串是否是空白的:没有任何字符,或者只包含空格符。

Clojure启航  Clojure 第2张

Clojure版本要短得多。但更重要的是,它更加简单:没有变量,没有可变状态,也没有分支结构。这要归功于高阶函数(higherorder functions)。

高阶函数本身也是一个函数,它接受其他函数作为参数;也可以把函数作为返回值。every?函数接受一个函数f和一个容器(collection) c作为它的参数,对于容器c中的每个元素,如果函数f都返回真的话,every?函数也就返回真。

由于Clojure的这个版本没有分支结构,所以无论是阅读还是测试都更容易。在大一些的程序中,这种优势还将会进一步扩大。而且,简洁的代码也更具可读性。

Clojure的这段程序读起来就像是一份关于何为空白的定义:如果一个字符串中的每个字符都是空格,那么这个字符串就是空白的。这要比一般的方法好太多了,在那些方法中,对空白的定义被隐藏在了由循环和分支语句组成的实现细节背后。

Clojure启航  Clojure 第3张

Clojure启航  Clojure 第4张

Clojure启航  Clojure 第5张

Clojure 版本的Person 是不可变的。

不可变数据结构生来就是线程安全的,Clojure 中可以通过使用引用、代理和原子来更新数据。

记录(record)是不可变的,Clojure也就自动提供了正确的hashCode()和equals()实现。

Clojure是Lisp的再度崛起Clojure是一种Lisp方言。

● Clojure必须成功地说服Lisp程序员,作为一种Lisp方言,Clojure包含了Lisp的关键部分。

● 同时,Clojure 需要成功地赢得广泛的程序员社区支持,而这正是过去那些Lisp的失败之处。

Clojure提供了Lisp元编程能力,与此同时还包含了一整套增强的语法,使得Clojure对于非Lisp程序员而言显得更为友好。

为什么是LispLisp的语言核心非常小,几乎没有什么语法,但却提供了一个强大的宏设施。

借助这些特性,可以根据需要对Lisp随意地直接定制。这样就不必使用其他那些绕来绕去的方式了。

Clojure启航  Clojure 第6张

getFirstName()是一个方法(method)。方法具有多态性,可以根据需要加以调整。

● 重新定义private:对于产品代码保持私有,但允许来自序列化(serialization)和单元测试代码的访问。

● 重新定义class:自动为每个私有字段都生成getters和setters,除非另有指示。

● 创建class的一个子类,提供面向生命周期事件的回调钩子。

对于“可感知生命周期”的类而言,只要创建了这个类的一个实例,就会激发相应的事件。

由于缺乏这些特性,程序员们不得不去借助一些重复性的、容易出错的变通方法。结果是,人们在这上面白白浪费了数百万行的代码,而罪魁祸首就是编程语言中类似特性的缺失。对大多数编程语言而言,只能祈求语言的实现者们尽快增加上面提到的这类特性。但在Clojure中,能凭借宏来自行添加属于自己的语言特性。

事实上,Clojure本身就是用宏来进行扩建的,比如defrecord。

Clojure启航  Clojure 第7张

如果需要的语义与此不同,写一个自己的宏就行。比如记录的一个变种,它具备强类型并具有可选的空字段校验能力,可以创建自己的defrecord宏。

Clojure启航  Clojure 第8张

这种对语言进行再编程,从而改变语言自身的能力,是Lisp的独门优势。

● Lisp具有同像性(homoiconic)。Lisp代码其实就是Lisp数据。这样就很容易让程序自己去编写其他的程序。

● 这就是语言的全部,且始终如此。

Lisp语法也废除了运算符优先级和结合性的规则。凭借完全的括号表示法,就能避免产生任何这方面的歧义。简单、整齐的Lisp语法也存在负面因素,至少对于初学者而言,成堆的括号,以及将列表作为核心数据类型都会成为一种障碍。

它是Lisp,但括号少了● Clojure泛化了Lisp的物理列表,将其抽象为序列(sequence)。这样既保留了列表的强大能力,同时还将这种能力扩展到了其他各种类型的数据结构。

● 依托于Java虚拟机,Clojure提供了一个范围广泛的标准库及部署平台。

● Clojure 提供的符号解析和语法引述(syntax quoting)方式,使得编写许多普通宏的时候更加容易了。

Clojure保留了括号表示法(当然也保留了Lisp的强大!)。

● 在Clojure中,除列表之外,还提供了更为便利的正则表达式、映射表、集合,向量和元数据等多种数据结构的字面表示语法。这些特性使得Clojure代码相比其他多数Lisp语言而言,过度列表化(listy)的症状要轻很多。

Clojure启航  Clojure 第9张

向量令参数列表变得非常醒目,也使得Clojure的函数定义更易于阅读。

● 与大多数Lisp语言不同,在Clojure中,逗号就是空格。

Clojure启航  Clojure 第10张

● 地道的Clojure不会内联不必要括号。

cond对一组成对的“测试/结果”逐个求值,当遇到第一个求值结果为真的测试时,返回其对应的结果。

Clojure启航  Clojure 第11张

在Clojure中则避免了额外的括号

Clojure启航  Clojure 第12张

这是一种审美决定,且双方都各有其支持者。但重点在于,Clojure获得了在不减损Lisp威力的前提下,尽可能减少过度列表化的机会。Clojure是一种卓越的Lisp方言,无论对于Lisp专家,还是Lisp新手,皆是如此。

Clojure是函数式语言Clojure虽然是一种函数式语言,但不像Haskell那样纯粹。

● 函数是一等公民。换言之,函数能在运行期间被创建,被当做参数传递,被用作返回值,并且能像其他数据类型那样,被用于各种用途。

● 数据是不可变的。

● 函数是纯粹的,也就是说,它们不会造成任何副作用。

Clojure启航  Clojure 第13张

● 非常简单,没有任何循环结构、变量或是可变的状态;

● 线程安全,不需要锁机制即可得到保证;

● 可并行化,无需修改代码,就可以将单独的步骤转移至多个线程;

● 非常通用,乐曲库可以是一个普通集合、XML或是一个数据库结果集。

函数式程序与命令式程序形成鲜明对比,在命令式程序中,是用显式的语句来改变程序状态的。

● 对函数式编程的需要,比以往任何时候都显得更加迫切。

● 当确实需要对状态进行修改时,纯粹的函数式编程语言就显得颇为尴尬了。

Clojure则通过软事务内存(STM,software transactional memory)及引用、代理、原子和动态绑定,提供了结构良好的机制用于处理可变状态。

● 许多函数式语言都是基于静态类型的。而Clojure的动态类型系统,使得程序员学习函数式编程更加容易。

● Clojure的Java调用方式是非函数式的。

Clojure 中不必显式锁定,就允许并发地更改状态。这种方式是 Clojure 函数式核心的有力补充。

Clojure简化了并发编程Clojure支持函数式编程,使得编写线程安全的代码非常容易。

由于不可变数据结构在任何时候都不会被修改,因此避免了数据会被另外一个线程破坏的危险。

当需要引用可变数据时,Clojure会通过软事务内存对其加以保护。在线程安全方面,相比Java提供的锁定机制,软事务内存是一种更高级的方法。可以借助事务来保护共享状态,而不是去琢磨那些既脆弱,又易于出错的锁定策略。

Clojure启航  Clojure 第14张

ref函数创建了一个引用,代表数据库的当前状态,这个引用会得到事务的保护。更新操作实在是微不足道。

Clojure启航  Clojure 第15张

dosync 开启了一个事务,允许对accounts 进行更新。这样既确保了线程安全,同时也比锁机制更容易使用。得益于事务,不必再操心应该锁定哪些对象,以及应该以什么顺序来锁定等等问题。

在一些常见的使用场景中,因为读取操作不会被阻塞,所以事务机制能够非常高效地运转。虽然这是个微不足道的例子,但其展现的技术是通用的,完全可用于解决现实世界中的问题。

Clojure与Java虚拟机彼此亲密无间从Clojure访问Java,清晰、简单、直接。能直接调用任何JavaAPI。

Clojure启航  Clojure 第16张

Clojure为调用Java提供了很多语法糖。

Clojure启航  Clojure 第17张

Clojure提供了简单的函数用于实现Java接口,以及从Java基类派生。此外,Clojure的所有函数都实现了Callable和Runnable接口。

Clojure启航  Clojure 第18张

Thread是这个实例的类名,然后Thread[Thread-0,5,main]是这个实例的toString方法返回值。

由于在Clojure中调用Java程序的语法干净而且简单,作为Clojure的惯例,会更加倾向于直接对Java进行调用,而不是把Java隐藏到一层Lisp化的封装背后。

评论列表暂无评论
发表评论
微信