鲍勃大爷:为何选择Clojure?

19-08-23 banq

我用许多不同的语言编写了系统; 从汇编程序到Java。我用二进制机器语言编写程序。我用Fortran,COBOL,PL / 1,C,Pascal,C ++,Java,Lua,Smalltalk,Logo和其他几十种语言编写了应用程序。我使用了静态类型语言,有很多类型推断。我用过无类型语言。我使用了动态类型语言。我使用了像Forth这样的基于堆栈的语言,以及像Prolog这样的基于逻辑的语言。

在过去的五十年里,我使用了很多不同的语言。(应该改称鲍勃大爷)

我得出了一个结论。

我最喜欢的语言是Lisp, 我认为这种语言将比其他语言更耐用,我相信这种语言最终将成为所有程序员使用的标准语言......

我不是Lisp的粉丝。40年来,我不是Lisp的粉丝。我看到CARs和CDRs和CADDADDRs,并认为这只是学术上的胡扯; 有趣但不是真正有用。

然后,十年前我找到了SICP。之后我找到了Clojure。Clojure是一个Lisp,它位于Java生态系统之上(并且没有CARs或CDRs或CADADAADRs)。

我没有立刻相信Clojure。花了几年时间。但是在经常磕磕绊绊和沮丧之后,我开始意识到这种语言是我用过的最简单,最优雅,最不那么强大的语言 - 而且不是很小。

那么,为什么这么看好Clojure?我已经列了一份清单。你准备好了吗?

1. 表达经济

如果您想知道这份清单列表的其余部分在哪里,那是存在的,这就是原因,只有一个。

在Clojure中编写富有表现力的代码更简单,更容易,更少遮挡。它需要更少的行。它需要更少的字符。它需要更少的时间。它需要较少的心理体操。

为什么会这样?答案很简单。的确答案是:非常简单。

该语言几乎没有语法或语法

解释这一点的最佳方法可能是向您展示一个例子。所以,在这里,为了您的娱乐,是打印前25个整数方块的程序:

(println (take 25 (map #(* % %) (range))))

我们来看看这里的语法:

  • ( 意思是:开始一个list。
  • ) 意思是:list结束。
  • 名称就是名称,在这种情况下都是函数。
  • * 是乘法函数的名称。
  • # 表示:将下一个list解释为函数。
  • % 意思是:该函数的第一个参数。

你刚刚看到Clojure语法的80%左右。

首先是那个“(”符号。这意味着它与“)” 之间的所有内容都是一个list。在大多数情况下,Clojure将list解释为函数调用。在这种情况下,函数是println。这只是类似我们习惯用Java 的System.out.println。

我们传递的是println什么?我们传递了take函数的结果。该take函数需要两个参数。第一个25是take的项目数;第二个参数是一个list。因此,这个take函数将返回一个list,其中包含第二个参数中list的前25项。

第二个参数中的list是什么?这是调用map函数的结果。该map函数需要两个参数。第一个是函数,第二个是list。该map函数将返回一个list,该list是在传入list的每个元素上调用传入函数的结果。

传入map的函数是什么?它是由#创建的匿名函数,它只是简单地调用它复制的第一个参数,这是%的意思。

什么list被传入map?它是通过调用range函数返回的list,该range函数只返回“所有”非负整数的list列表。该列表是惰性的,因此实际上只会生成上游函数所需的整数。

有些人不喜欢%语法的复杂性,所以我们可以创建一个square函数如下:

(defn square [x] (* x x))
(println (take 25 (map square (range))))

defn定义了一个名为square新函数,括号[]定义了一种称为向量的不同类型的“list列表”。list列表具有链接列表的运行时复杂性。向量具有数组的运行时复杂性。无论如何,在这种情况下,向量告诉defn该square函数需要一个名为的参数x。其余你应该能够推断出来。

这使第二行更好一些理解。该map函数只是调用square。

现在你已经看到了Clojure大约90%的语法。

现在让我们将它与等效的Java程序进行比较:

public class SquaresOfIntegers {
  public static void main(String[] args) {
    for (int i=0; i<25; i++)
      System.out.println(i*i);
  }
}

(banq注:被Java洗脑的我一眼看到这份代码,顿然一目了然,一下子明白了,Clojure表达的那么拧巴,Clojure和Java大概是文言文和白话文的区别,文言文确实很简单,读懂文言文的人惜字如金)

即使你不计算封闭的类,这也更加冗长。然而,更重要的是,这涵盖了大约5%的Java语法。并且不要让我开始与C ++进行比较。

现在我不想说明这一点。经过与语言之后的语言比较,我可以继续比较。底线是Clojure的语法比大多数语言小得多。这种最小的语法意味着我能够比大多数其他语言更清楚,更直接地表达问题。

看,我很难啊。我当时是一名C ++程序员。更重要的是,我(不再是)是一名C ++语言律师。我沉迷于该语言的重量级语法。我被所有可爱的“fidelty bits”迷住了。二十年前,我发现向Java过渡到相当“meh”。它只是一个精简的C ++(它之后变得更加肥胖)。

但是我向Clojure的过渡令人大开眼界。基于轻量级语法,我希望它适用于一些课堂练习,但不适用于构建大型系统。在我看来,大型系统等同于大型语法。孩子,我错了。

相反,我发现Clojure的最小语法比Java或C ++的更重的语法更有利于构建大型系统。事实上,这不是一场竞赛。构建大型系统是Clojure比我使用的任何其他语言更简单,更容易。

正如我在开始时指出的那样,我使用了很多语言。

但是关于…?

所以你可能有一些抱怨,问题,异议等等。让我看看我是否可以预料到它们:

我的天啊!所有这些括号

你几岁啊…?睁开大眼看看,这是一个java函数调用:f(x)。现在这里是Clojure中相应的函数调用:(f x)。你在那里看到任何额外的括号吗?

好的,嘻嘻,这不完全公平。我们最后会看到一些括号,但那只是因为我们倾向于嵌套函数调用。看看上面的整数程序,你会明白为什么。不要担心,如果你真的不喜欢那种嵌套语法,你总是可以使用线程宏(让读者理解)。

但是不是很慢吗?

不,Clojure并不慢。哦,看,它不是C.它不是汇编程序。如果纳秒是您的关注,那么您可能不希望Clojure在您最内层的循环中。您可能也不想要Java或C#。但是我们现在编写的99.9%的软件不需要纳秒性能。我使用Clojure 构建了一个基于GUI的实时动画太空战游戏。即使屏幕上有数百个物体,我也可以将帧速率保持在20s 。Clojure并不慢。

但是Javascript怎么样?

ClojureScript编译到Javascript并在浏览器中运行就好了。实际上,我上面提到的太空战计划是使用ClojureScript编译的,并且在浏览器中以比本机模式更高的帧率运行(我还在试图解决这个问题。)

但它是动态类型的!

动态类型必须写测试,不是吗?作为测试的一部分,您可以使用clojure/spec库来指定类型的模式,并使用前置条件和后置条件(按合同样式设计)进行动态检查,让您心满意足。

但它是动态类型的[2] !!

类型声明是需要语法成本的。而语法成本的加入会降低表达的经济性。

但是,Dammit,它是动态类型的!

好的我明白了。你喜欢静态类型。很好,你可以使用一个很好的静态类型语言,我将使用Clojure。我们之前还在苏格兰呢。

那IDE呢?

带有Cursive插件的IntelliJ非常好用。大多数Clojure程序员使用Emacs。

重构怎么样?

带有Cursive的IntelliJ有一些很好的重构; 虽然他们还没有“提取方法”(来吧伙计!)

Java互操作怎么样?

没问题。Clojure程序可以直接调用Java。Java程序只需要一点点修改就可以调用Clojure程序。Interop不应该是您关注的问题。

我在哪里可以找到Clojure程序员?​​​​​​​

他们在那里; 但你最好还是编写它们。语法很简单。您可能已经知道Java平台。只需决定在Clojure中构建您的下一个系统。花一两个星期习惯这门语言。然后开始哦,当你在几个月的时间里,你会意识到你早期的东西是多么原始,你会被诱惑去清理它。但还有什么是新的?

但是那是一种新语言.

是的,每个月都有新的语言。每周。每天。我们不乏新语言。关于这些新语言的事情是,任何一种语言都没有新的东西。它们只是由他们在一个罐子里切割和震动的旧语言组成,然后在Yahtzee的语言游戏中抛弃。

好的,那不完全公平。在语言空间中仍有一些好的想法渗透。但这些想法都不是革命性的。我们进入了“调整”的时代。我没有发现任何新语言几乎与Clojure一样引人注目,仅仅因为几乎所有语言都具有额外的语法。

其他语言的语法也很少。为什么不能成为选择之一?

是的,这是真的。Forth有一个很小的语法。Smalltalk也是如此。但是这两种语言都有自己的包袱。Forth是一种后缀表达式(将运算符写在操作数之后) 语言。Forth的短语并不是表达经济。虽然我发现基于它的PostScript很有趣。

Smalltalk小而优雅,美丽。它催生了设计模式革命。它催生了重构革命。它催生了TDD革命。它有助于产生敏捷革命。Smalltalk是一种具有巨大影响力的语言。

Smalltalk也是一种基于图像的语言。很少有程序员能够将自己的想法包含在真正意义上的内容中。不幸的是,与所有基于文本文件的语言相比,语言萎缩了。

到目前为止,Lisp比Smalltalk或Forth更老。它创建于1957年,源自30年代的概念,并且从未像Smalltalk和Forth那样萎靡不振。的确,这是拒绝死亡的语言。我们试图杀了很多次。但就像令人讨厌的邻居流浪猫一样,它会......继续......回来。

最后,Lisp功能齐全。未来看起来非常实用。​​​​​​​

 

                   

4
猜你喜欢