Clojure 和 Scala 相比的优劣

by admin on 2020年4月22日

代码世界即将加入一门新成员:Lux。你没看错,它不是洗发水,而是古老的 Lisp
家族中新诞生的函数式语言。

澳门新葡亰网址下载,编程语言 – Clojure 和 Scala 相比的优劣 – SegmentFault
https://segmentfault.com/q/1010000000679980

详述三种现代JVM语言–Groovy,Scala和Clojure – 推酷
http://www.tuicool.com/articles/jYzuAv

目前 Lux 还在研发之中,最新版本是 0.5.0。它可被用来编写一系列在 JVM
(Java 虚拟机)上运行的程序。但它的语义并不是与 JVM 绑定的,因此,Lux
应该被理解为是一门通用语言
,被设计用来尽可能多平台地进行程序表示。但同时,它要能够深入每一个特定平台,实现后者的丰富功能。

Scala 认为 OO 和 FP
都是非常有效的表达方法,因此在语言中同时支持它们。Clojure
则强烈不鼓励使用 OO 编程,尽管从与 Java
互通等方面出发有一些支持。它强烈倾向于 FP 编程。带来的后果是 Scala
的程序风格可能会非常多样,而 Clojure 则相对统一。

Java的遗产将是平台,而不是程序设计语言。

澳门新葡亰网址下载 1


Clojure是最激进的,它的语法是从其它语言中分离出来,被认为是Lisp的方言。Clojure是强动态类型语言(就像Groovy),它反映了一种义无反顾的设计决策。虽然Clojure允许你与遗留的Java程序进行全面而深度的交互,但是它并不试图构建一座桥梁去连接面向对象范式。

作为新语言,它有何特别之处?

想知道:
这两种语言相比,各有什么优缺点
语言哲学
适用环境


Lux
是纯粹的函数式编程语言
,它采用了严格计算(eager-evaluation)而非惰性计算,来提高逻辑简洁性,而适当牺牲性能和程序行为。这门语言受到
Haskell、Clojure 和 ML 的启发。其中,Clojure,这门同样基于 Lisp、面向
JVM 的主流语言,是  Lux 的首要启发来源。但和 Clojure 不同的是,Lux
采用了静态类型(statically
typed)以提高性能并减少漏洞。

希望这方面的大神给详解一番。

ZDNet至顶网开发频道消息 在我与Martin
Fowler曾经合作呈现的一次主题演讲中,他作出了一个有洞察性的观点:
Java的遗产将是平台,而不是程序设计语言。
Java技术的原始工程师们作出了一个明智的决定,就是将编程语言与运行时环境分开,最终这使得超过200种语言能够运行在Java平台上。这种架构对于该平台的长期活力是至关重要的,因为计算机程序设计语言的寿命一般都是比较短。从2008年开始,由Oracle主办的一年一度的JVM语言峰会为JVM上其它的语言实现与Java平台工程师进行开放式合作提供了机遇。
欢迎来到Java.next专栏系列,在本系列的文章中,我将讲述三种现代JVM语言–Groovy,Scala和Clojure–它提供了范式,设计选择与舒适因子之间一种有趣的混合。在此我不会花时间去深入介绍每种语言;在它们各自的站点上都有这类深度介绍。但这些语言社区的站点–它们主要目的是为了传布这些语言–都缺乏客观的信息,或者是该语言不适用的例子。在本系列的文章中我将进行独立地比较,以填补上述空白。这些文章将概述Java.next程序设计语言,以及学习它们的好处。
超越Java
Java程序设计语言达到卓越的程度就是,按Bruce Tate在他的Beyond
Java一书中的说法,完美风暴:Web应用的兴起,已有Web技术由于种种原因不能适应需求,企业级多层应用开发的兴起,这些因素共同造就了Java的卓越。Tate也指出这场风暴是一系列独一无二的事件,曾经没有其它语言使用相同的途径达到相同的卓越程序。
Java语言已经证明其在功能方面的强大灵活性,但它的语法与固有范式则存在着长期已知的局限性。尽管一些承诺过的变化即将引入到该语言中,但Java语法却不能很容易地支持一些重要的未来语法特性,例如函数式编程中的某些特性。但如果你试图去找到一种语言去替代Java,那么你就找错了。
多语言编程
多语言编程–在2006年的一篇博客中我使这个术语重焕活力并重新流行起来–是基于这样的一种认识:没有一种编程语言能够解决每个问题。有些语言拥有某些内建的特性,使其能够更好地适应特定的问题。例如,由于Swing十分复杂,开发者们发现很难编写Java中的Swing
UI,因为它要求事先声明类型,为UI动作定义烦人的匿名内部类,还有其它的麻烦事儿。使用更适合构建UI的语言,如Groovy中的SwingBuilder工具,去构建Swing应用会美妙得多。
运行在JVM上的程序设计语言大量增多,这大大激发了多语言编程理念,因为你可以混用编号语言,并可使用最佳匹配的语言,但同时却维护着相同的底层字节码和类库。例如,SwingBuilder并不是要替代Swing;它只是搭建在已有的Swing
API之上。当然,在相当长的时间内,开发者们还是将在JVM之外混合使用编程语言–例如,为特定目的而使用SQL和JavaScript–但在JVM的世界内,混合编程将变得更为流行。ThoughtWorks中的许多项目就合用着多种编程语言,而所有由ThoughtWorks
Studios开发的工具则都要使用混合语言。
即便Java仍是你主要的开发语言,学习一下其它语言是如何工作的会让你将它们纳入你的未来战略中。Java仍将是JVM生态系统中的重要组成部分,但最终它更多是作为该平台的汇编语言–或是由于纯粹的性能原因,或是在应对特殊需求时才会用到它。
编程语言的进化
当上世纪八十年代我还在大学时,我们使用着一种称作Pecan
Pascal的开发环境。它独一无二的特性就是能使相同的Pascal代码既可运行在Apple
II上,又可以运行在IBM
PC上。Pecan的工程师们为了实现这一目的使用了一种称作”字节码”的神秘之物。开发者们将他们的Pascal代码编译成”字节码”,该”字节码”则运行在为各个平台编写的原生”虚拟机”上。那是一段可怕的经历!最终程序慢的出奇,即便只是一个简单的类赋值。当时的硬件无法应对这一挑战。
Pecan
Pascal之后的十年,Sun发布了使用相同架构的Java,它受限也受利于上世纪九十年代的硬件环境。Java还加入了其它的对开发者友好的特性,如自动的垃圾收集。由于曾经使用过像C++之样的语言,现在我再也不想使用没有垃圾收集功能的语言去编码了。我宁愿花时间在更高抽象层次上去思考复杂的业务问题,而不是像内存管理这样的复杂管道问题。
计算机语言通常没有很长寿命的原因之一就是语言和平台设计的创新速度。由于我们的平台变得更为强大,它们可以处理更多的额外工作。例如,Groovy的内存化(memoization)特性(2010年加入)会缓存函数调用的结果。不需要手工编写缓存代码,那样会引入潜在的缺陷,你仅仅只是需要调用memoize方法而以,如清单1所示:
清单1. 在Groovy中内存化函数
def static sum = { number ->
factorsOf(number).inject(0, {i, j -> i + j})
}
def static sumOfFactors = sum.memoize()
在清单1中,sumOfFactors方法返回的结果会被自动缓存。你还可以使用方法memoizeAtLeast()和memoizeAtMost()去定制缓存行为。Clojure也含有内存化特性,在Scala中也有略有实现。像内存化这样存在于下一代编程语言(以及某些Java框架)中的高级特性也将逐渐地进入到Java语言中。Java的下一个版本中将加入高阶函数(higher-order
function),这使得内存化更容易被实现。通过研究下一代Java语言,你就可以先睹Java的未来特性为快了。
Groovy,Scala和Clojure
Groovy是二十一世纪的Java语法–浓缩咖啡取代了传统咖啡。Groovy的设计目标是更新并消除Java语法中的障碍,同时还要支持Java语言中的主要编程范式。因此,Groovy要”知晓”诸如JavaBean,它会简化对属性的访问。Groovy会以很快的速度纳入新特性,包括函数式编程中的重要特性,这些特性我将在本系列的后续篇章中着重描述。Groovy仍然主要是面向对象的命令式语言。Groovy区别于Java的两个基本不同点:它是动态而非静态的;它是的元编程能力要好得多。
Scala从骨子里就是为了利用JVM而进行设计的,但是它的语法则是完全被重新设计过了。Scala是强静态类型语言–它的类型要求比Java还严格,但造成的麻烦却很少–它支持面向对象和函数式范式,但更偏好于后者。例如,Scala更喜欢val声明,这会生成不可变变量(类似于在Java中将变量声明为final)赋给var,而var将创建更为大家所熟悉的可变变量。通过对这两种范式的深度支持,Scala为你可能想要的(面向对象的命令式编程)与你所应该想要的(函数式编程)之间架起了一座桥梁。
Clojure是最激进的,它的语法是从其它语言中分离出来,被认为是Lisp的方言。Clojure是强动态类型语言(就像Groovy),它反映了一种义无反顾的设计决策。虽然Clojure允许你与遗留的Java程序进行全面而深度的交互,但是它并不试图构建一座桥梁去连接面向对象范式。例如,Clojure是函数式编程的铁杆,也支持面向对象以允许与该种范式进行互操作。尽管它支持面对对象程序员所习惯的全部特性,如多态–但,是以函数式风格,而非面向对象风格进行实现的。设计Clojure时遵循了一组核心的工程原则,如软件事务内存(Software
Transactional Memory),这是为了迎合新功能而打破了旧有的编程范式。
编程范式
除语法之外,这些语言之间的最有趣的不同之处就是类型及其内在的编程范式:函数式或命令式。
静态类型 vs. 动态类型
编程语言中的静态类型要求显式的类型声明,例如Java中的int
x;声明语句。动态类型语言并不要求在声明时提供类型信息。此处所考虑的语言都是强类型语言,意即程序在赋值之后能够反射出类型。
Java的类型系统广受诟病之处就是其静态类型有太多不便,且又没有提供足够的益处。例如,在当前的有限的类型推导出现之前,Java要求开发者在赋值语句两边要重复地声明类型。Scala的类型比Java的更为静态,但在日常使用中所遇到的不便要少得多,因为它大量使用了类型推导。
初看Groovy,它似乎有一种行为能够衔接静态与动态之间的隔阂。考虑如清单2所示的简单对象集合工厂:
清单2. Groovy集合工厂
class CollectionFactory {
def List getCollection(description) {
if (description == “Array-like”)
new ArrayList()
else if (description == “Stack-like”)
new Stack()
}
}
清单2中的类表现为一个工厂类,基于传入的description参数,该工厂返回List接口的两种实现–ArrayList或Stack–之一。对于Java开发者,上述代码确保了返回值能够符合约定。然后,清单3中的两个单元测试揭示了一种复杂性:
清单3. Groovy中的集合类型测试
@Test
void test_search() {
List l = f.getCollection(“Stack-like”)
assertTrue l instanceof java.util.Stack
l.push(“foo”)
assertThat l.size(), is(1)
def r = l.search(“foo”)
}
@Test(expected=groovy.lang.MissingMethodException.class)
void verify_that_typing_does_not_help() {
List l = f.getCollection(“Array-like”)
assertTrue l instanceof java.util.ArrayList
l.add(“foo”)
assertThat l.size(), is(1)
def r = l.search(“foo”)
}
在清单3中的第一个单元测试中,使用前述的工厂类获得一个Stack对象,并验证它是否确实是Stack对象,然后再执行栈操作,例如push(),size()和search()。然而,在第二个单元测试中,我必须声明一个期望的异常MissingMethodException才能确保该测试能够通过。当我获取一个Array-like的集合,并将它赋给List类型的变量时,我能够验证返回的类型确为一个List对象。但是,当我试图调用search()方法时将触发异常,因为ArrayList并不包含search()方法。因此,这种声明无法在编译时确保方法的调用是正确的。
虽然这看起来像是一个缺陷,但这种行为却是恰当的。Groovy中的类型只是确保赋值语句的有效性。例如,在清单3中,如果返回的实例未实现List接口,将会触发一个运行时异常GroovyCastException。鉴于此,可以肯定Groovy能够与Clojure同跻身于强动态类型语言家族。
然而,Groovy最新的一些变化使得它的静态与动态之间的隔阂变得扫地清。Groovy
2.0加入了注解@TypeChecked,该注解可使你特别地对类或方法决定进行严格的类型检查。清单4例证该注解的使用:
清单4. 使用注解的类型检查
@TypeChecked
@Test void type_checking() {
def f = new CollectionFactory()
List l = f.getCollection(“Stack-like”)
l.add(“foo”)
def r = l.pop()
assertEquals r, “foo”
}
在清单4中,我加入了注解@TypeChecked,它同时对赋值及随后的方法调用进行了验证。例如,清单5中的代码将不能通过编译:
清单5. 防止无效方法调用的类型检查
@TypeChecked
@Test void invalid_type() {
def f = new CollectionFactory()
Stack s = (Stack) f.getCollection(“Stack-like”)
s.add(“foo”)
def result = s.search(“foo”)
}
在清单5中,我必须对集合工厂返回的对象进行强制类型转换,这样才能允许我调用Stack类中的search()方法。但这种方式会产生一些局限性:当使类型静态化之后,Groovy的很多动态特性将无法工作。然而,上述救命证明了Groovy将继续进行改进,以弥合静态性与动态性之间的分歧。
所有这些语言都有十分强大的元编程功能,所以更为严苛的类型化可以在事后再添加进来。例如,已有多个分支项目将选择性类型(selective
type)引入到Clojure中。但一般认为选择性类型是可选的,它不是类型系统的一部分;它只是一个类型验证系统。
命令式 vs. 函数式
另一个主要的比较维度就是命令式与函数式。命令式编程注重于单步执行的结构,在许多情况下,它是模仿了早期底层硬件的有益结构。函数式编程则注重将函数作为第一等的结构体,以试图将状态传递与可变性降低到最小。
Groovy在很大程度上是受Java的启发,它在根本上仍然是命令式语言。但从一开始,Groovy就加入了许多函数式命令的特性,并且以后还会加入更多的此类特性。
Scala则弥合了这两种编程范式,它同时支持这两种范式。在更偏向(也更鼓励)函数式编程的同时,Scala依然支持面向对象和命令式编程。因此,为了恰当地使用Scala,就要求团队要受到良好的培训,以确保你不会混用和随意地选择编程范式,在多范式编程语言中,这一直都是一个危险。
Clojure是铁杆的函数式编程语言。它也支持面向对象特性,使得它能够很容易地与其它JVM语言进行交互,它并不试图去弥合这两种范式之间的隔阂。相反,Clojure这种义无反顾的决策使它的设计者所考虑的语句成为很好的工程学实践。这些决策具有深远的影响,它使Clojure能够以开创性的方法去解决Java世界中一些挥之不去的问题(如并发)。
在学习这些新语言时所要求的许多思想上的转变就是源自于命令式与函数式之间的巨大差别,而这也正是本系列文章所要探索的最有价值的领域之一。

澳门新葡亰网址下载 2

2014年09月18日提问
评论
邀请回答
编辑
更多****

Lux 允许开发者通过编程创造新类型,这会提供动态类型语言(dynamically
typed )所具有的灵活性。函数式语言 Haskell 有类型类(type
classes),而雷锋网获知, Lux
的约束性不会这么强——想要绕过任何约束可在语言中原生实现,而不需要黑入类型系统。

默认排序时间排序
2个回答
答案对人有帮助,有参考价值
2答案没帮助,是错误的答案,答非所问

Lisp 开发于 1958
年,是最早的用于人工智能的编程语言。现在用的人虽然少了,但多门基于
Lisp 的变种、或者说子孙语言,仍然占有重要地位。这些基于 Lisp
的语言,使得开发者进行元编程(metaprogramming)成为了可能——改变语言本身的行为,或者编写能写代码的代码。Lux
通过与 Lisp 类似的宏(macros)来实现这一点,但这同时把 Lux
的编译器暴露为语言中的一件物体。通过这种方式,Lux
可以定制能被用户重写的模型匹配系统( pattern-matching systems )。

采纳

澳门新葡亰网址下载 3

首先声明,我主要使用 Clojure 编程,学习和评估过
Scala,但没有在具体工作中使用 Scala 的经历。因此很可能有偏见。
Scala 和 Clojure 都是基于 JVM 平台上的通用语言,其中 Scala
语言的历史更加悠久一点。
先说一些共同点:
都试图利用成熟的 JVM,并可以使用 JVM
平台上现存的代码和广泛的库,同时避免 Java 语言表达上的一些弱点。
两者都试图将函数编程 (FP) 引入到原本是为纯 OO 语言 Java 定制的 JVM
上。因此,它们都具有 FP
的特征:函数是头等公民,可以作为参数传递,可以作为返回值返回。

雷锋网获知,尽管提供了与 Java 的交互操作,Lux 会专注于函数式编程。

但两种语言的设计哲学截然不同:
Clojure 是历史悠久的 Lisp 的一种方言,它需要尊重 Lisp
的传统:包括臭名昭著(对 Lisp 爱好者是香味扑鼻)的括号海洋。当然 Clojure
做了很多不同传统 Lisp 的处理,如引入了 Vector,map 等基本类型,而不只是
List。而 Scala 是全新设计的语法,它不受过往语法的限制;它深受 Haskell
的影响,有抽象数据类型 ADT、 模式匹配等鲜明特征。
Scala
是强类型语言,编译器积极检查数据类型,有类型推断等新类型语言的先进特征。Clojure
是鸭子类型语言,编译器不检查类型,这责任在于程序员自己(目前 core.typed
库试图把强类型检查作为可选项加入到 Clojure
语言中,不过还远远不到成熟的地步)。
Scala 认为 OO 和 FP
都是非常有效的表达方法,因此在语言中同时支持它们。Clojure
则强烈不鼓励使用 OO 编程,尽管从与 Java
互通等方面出发有一些支持。它强烈倾向于 FP 编程。带来的后果是 Scala
的程序风格可能会非常多样,而 Clojure 则相对统一。
Scala
是传统的语言开发方式:有相当多的关键字和语法糖,都需要核心开发者支持。虽然加入了元编程能力,但其元编程与普通编程区别很大,难以被一般开发者使用。
Clojure 从 Lisp
处继承的代码即数据的核心,则保证了极为自然和强大的元编程能力,任何开发者都很容易用宏来定义自己的语法,因此基于
Clojure 定义自己的领域语言(DSL)非常容易。
由于其多样的语法特点,多种语义的支持,Scala
是一种相当复杂的语言,其语法的数量比 Java 语言还要多,更不要说其独立于
Java 的自己的类型系统。与之相对,Clojure
的内核非常简单,语法极为简化。一个重要的后果是,Clojure
成熟较快,编译器本身容易开发,而 Scala
的编译器开发难度大得多。我本人是在评估了两种语言的稳定性后做出的选择。

Lux 的开发者团队表示:

两种语言都是通用性的,因此是互相竞争关系,都声称自己适合全领域的编程。虽说在具体的库支持上可能互有长短(比如
Clojure 的 STM 被认为是更容易进行并行编程,而 akka 这样的 actor 库可以让
Scala 具有 Erlang
一般的能力),但这些很可能是临时的。所以考虑到选择一种新的语言,特别是如此有特点的两种语言,需要做好颠覆三观的准备(特别是少接触
Lisp 的大多数程序员),然后根据自己的喜好进行选择。
PS. 有人提出 Clojure
的可读性不好,这点我非常不同意。这很可能是熟悉程度弱所带来的一种偏见。对于自己不熟悉的语法表达会有这种看法。实际上,由于
Clojure 的语法统一程度强,一般来说好的 Clojure
程序的一致性会更好。当然,你也可以用它写出很烂的完全不可读的程序,但哪种语言也无法避免这样的可能吧?
PPS. FP 与 OO 的编程逻辑截然不同,从 OO 为主转为 FP
需要大的习惯转变。但如果不进行这种转变,何必学习一种新的语言来表达呢?特别是
Java 8 也已经加入了相当的 FP 支持,可以在 OO 为主的环境中加入 FP
的味道了。另外,Clojure 并不是纯粹的 FP
语言,从实用性的角度上它支持相当多的可变性编程;更纯粹的 FP 语言是
Haskell,学院派(非爱好者的“不实用”的说法)的语言。

Lux
既简洁又复杂。它的设计允许你只用一个小的子集,就能创建出高效的程序。但
Lux
的目标是为我们提供有一系列强大工具的武器库,来满足开发者在各类项目中的不同需求。

2014年09月19日回答
·
2014年09月19日更新
评论
编辑

他们还表示,虽然函数式语言是学界人士做研究的最爱,但 Lux
为软件开发人员的日常工作而设计

对 Lux
感兴趣的程序猿们,可通过 GitBooks 获得它的详细介绍。顺便提醒一下,这有一本书那么厚。

澳门新葡亰网址下载 4

稿源:雷锋网

robertluo659
声望

答案对人有帮助,有参考价值
0答案没帮助,是错误的答案,答非所问

Clojure是个JVM上的Scheme,对于熟悉Lisp家族语言的人来说更容易上手,但由于它是个纯FP,所以代码的可读性不太好。
Scala号称JVM上的C++,是个OO+FP的混合体,整体看代码风格更接近Java,对于传统的Java开发者更容易接受。
从库/框架方面看,Clojure和Scala都可以使用各种Java包(没错,Clojure也可以使用Scala包,反之亦然),所以这方面其实没有太大差别。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图