Fogus在这篇帖子里介绍了过去5年间涌现出来的一些新的编程语言,就如作者本人所说,你并不需要也不可能掌握所有这些语言,但是花点时间了解下它们,或许你就会从中发现未来编程语言的演进趋势,原文介绍了14种语言(当然不止这些),由于篇幅太长,我将分两部分发布这篇文章:
-----------------------
前些天我编译了一个Perlis(译者注:Alan Perlis,第一届图灵奖得主)语言列表,目的就是为了向大家展示主流编程语言之外的广阔天地,这些语言只是为了拓展你的视野,就艺术性和实现上的技巧性而言,并没有什么过人之处。在今天这篇帖子里,我会向大家介绍一些相对较新的编程语言(让我们限定在过去5年之内),主要目的是展示这些语言中的一些有趣的特性,以及当前人们对旧有编程语言的认识,和对下一代语言发展方向的思考和探索,下面所列的这些语言有些可能已经停止开发了,但是在某种程度上它们依然代表了人们对于“新一代编程语言”的思考与探索,记住,这有时候并不意味着就是“创新”。
同我的Perlis列表不同,下面所列的这些语言我并没有花太多的时间去了解,所以,如果有错误还希望大家能够批评指正,另外,以下排名不分先后。
Shen
发布时间: 2011, 作者: Dr. Mark Tarver
在我的Perlis列表里,我介绍了Qi这门语言,所以在这里介绍它的继承者Shen就是理所当然的事情了,事实上,Shen和Qi的大部分(或者全部?)的特性都差不多:
* Lisp方言
* 可选静态类型
* 带保护的模式匹配
* 宏
* 交互式执行(Partial application)
* 函数回溯(backtracking)
* 内置Prolog
* 内置编译器
尽管如此,Shen实际上是Qi的进化版,Shen的很多点子都是继承自Qi,但是同Qi不同,它最主要的目标是靶向性(targetability),这是什么意思呢?Qi主要是以Common Lisp作为它的宿主语言,并在这方面花了大量精力,尽管如此,Qi的实现实际上只使用了Common Lisp的一个非常小的子集,因此,Tarver博士决定继承这个点子,并限定Shen只依赖一个叫做KI的最小化的Lisp语言核心,因此在理论上, 这让Shen可以更容易的移植到其它宿主语言上,比如Javascript,Python,Clojure以及Common Lisp等等,“kernel Lisps”曾经激起过我的无限遐想,Shen算是在这方面的一个比较成熟的实践。
下面是一个简单的使用了嵌入Prolog的member函数:
(defprolog member X [X | _] <--; X [_ | Y] <-- (member X Y);) (prolog? (member 1 [1 2 3])) /*=> true */
交互式执行(Partial application):
(* 2) /*=> #((* 2) 54) /*=> 108 */
下面这个函数用于计算第N个三角形数:
(define triangle 0 -> 0 N -> (+ N (triangle (- N 1)))) (triangle 100) /*=> 5050 */
这是上面那个函数的带类型限定的版本:
(tc +) /* turn on type-checking */ (define triangle {number --> number} 0 -> 0 N -> (+ N (triangle (- N 1)))) (triangle 5) /*=> 15 : number */ (triangle a) /* type error */
我们可以将Shen看作是Lisp漫长,蜿蜒的历史中的一个自然的进化,实际上许多现代语言只不过是从Lisp语言中吸收了其早在很多年之前就已经提出过的理念而已,因此,要说最令人激动语言,那仍然是Lisp本身。
更多资源:
* 官方网站
* 源码
* 15分钟学习Shen
Agda 2
发布日期:2009,作者: Ulf Norel
我曾试着想要全身心的投入到Agda语言中,但是关于它,我却不知从何说起,首先,Agda是一门纯函数式,模式匹配,独立类型的编程语言,并且,它还尝试实现辅助证明(proof assistants)。在独立类型的语言中,类型表达式可以包含一个程序表达式,因此,对类型的限定就只能通过函数语句或是值预测来解决,就实在是再遭不过了,Agda的类型语句和值语句是等价的(就是编程语句本身),这就意味着Agda的类型系统可以支持远比静态语言复杂的多的数据类型,比如,我们可以说这个函数只接受已经经过排序的列表类型(PDF),恩,让我们看个例子吧:
下面是一个Agda类型系统的奇偶数编码程序
data Nat : Set where zero : Nat suc : Nat -> Nat fortyTwo : Nat fortyTwo = 42 plus : Nat -> Nat -> Nat plus zero m = m plus (suc n) m = suc (plus n m) mutual even : Nat -> Bool even zero = true even (suc n) = odd n odd : Nat -> Bool odd zero = false odd (suc n) = even n
上面的代码定义了两个数据类型 1) 自然数 2)偶数,当然,你也可以定义类型函数作为前置操作符:
_+_ : Nat -> Nat -> Nat zero + m = m suc n + m = suc (n + m)
目前为止我对Agda的了解也就这些了,但是如果有时间,我希望可以对它做进一步的了解。
更多资源:
* The Agda Wiki
* 介绍资源
* 使用Agda的论文
* 源码
Ioke
发布日期:2008,作者:Ola Bini
Ola Bini的Ioke语言就是为了回答这样一个很简单的问题:如果完全不用考虑性能,而只专注于表达性(expressivity),那么你会创造怎样的一门语言出来?事实证明从Bini的PPT里你可以看到这门语言具有难以置信的可表达性(见下面链接),Ioke最有趣的一个特性就是它是一个支持宏的homoiconic语言(homoiconic指程序本身可以作为语言的一种数据结构来表示)。
myfor = dsyntax( "takes a name, an enumerable, and a transforming expr and returns the result of transforming each entry in expression, with the current value of the enumerable bound to the name given as the first argument", [argName, enumerable, argCode] ''(`enumerable map(`argName, `argCode)) ) myfor(x, 1..5, x*2) ;=> [2,4,6,8,10]
另一个促使我学习Ioke的动力就是:
牛逼的人创造的东西总是值得学习的。
不断将我们的能力推向边缘是作为程序员的职责所在,而学习聪明人的创造则是做到这点最有效的方式。
更多资源:
* Ioke
* Ioke: a Folding Language (视频)
* Ioke Wiki
* Announcement
* 源码
* Macro types in Ioke – or: What is a dmacro?
Pure
发布日起: 2008, 作者: Albert Gräf
Pure也是一个基于term rewriting构建的函数式编程语言,Term rewriting有点像是我们在高中代数里用到的FOIL(一种拆解多项式的方法)方法:
(x1 + y1) * (x2 + y2) = (x1 * x2) + // First (x1 * y2) + // Outer (y1 * x2) + // Inner (y1 * y2); // Last
上面的代码展示了如何使用FOIL方法来对两个多项式相乘进行变换,让我们来看看Pure可以做什么:
(x + 3) * (x + 5); //=> x*x+x*5+3*x+15
或许你认为答案应该是x^2 + 8*x + 15,但是因为我们没有定义消除冗余的操作,所以结果会是下面的样子:
x*x = x^2; (x + 3) * (x + 5); //=> x^2+x*5+3*x+15
这已经很接近了。
另一个更复杂的例子就是求解一个数的质因子:
factor n = factor 2 n with factor k n = k : factor k (n div k) if n mod k == 0; = if n>1 then [n] else [] if k*k>n; = factor (k+1) n if k==2; = factor (k+2) n otherwise; end; factor 138; //=> [2,3,23]
要说在这篇帖子里最让我佩服语言,就是属Pure了。
更多资源
* Pure wiki
* Albert Gräf访谈
* Term Rewriting and All That
* 源码
Go
发布时间: 2009,作者: Robert Griesemer, Rob Pike, and Ken Thompson
对于是否要在这篇贴子里介绍Go让我纠结了很久,到目前为止,我对Go都有非常强的抵触情绪,尽管如此,但是人们似乎觉得多一种系统级的编程语言选择是件好事情,所以最终我还是决定抛弃个人偏见,将Go包含在内。
下面是一段用Go编写的游程编码(run-length encoding)程序:
package main import ( "fmt" "strings" ) var order = 4 var grain = "*" func main() { t := []string{grain + strings.Repeat(" ", len([]int(grain)))} for ; order > 0; order-- { sp := strings.Repeat(" ", len([]int(t[0]))/2) top := make([]string, len(t)) for i, s := range t { top[i] = sp + s + sp t[i] += s } t = append(top, t...) } for _, r := range t { fmt.Println(r) } }
对于系统级编程,这个世界需要更多的选择,而Go正是针对这个目标设计的。
更多资源
* Official site
* 源码
* 指南
Arc
发布日起:2008,作者:Paul Graham以及Robert Morris
很难相信Arc居然只是一个3年前才诞生的语言(根据发布日期),当然,我之所以觉得它古老,这和我花了无数时间阅读Graham介绍Arc的帖子有关,在Arc发布之前,它曾让人无比激动,但不幸的是,在它真正发布之后,对这个语言的评价基本上都处于失望和生气之间,我也非常想要喜欢它,但是找来找去我还是没能找到充足的理由说服自己,我觉得如果没有Clojure,Racket或是Qi这样的语言,那么我或许会愿意去尝试下Arc,不过我必须得承认,Arc的核心理念“简明就是力量”仍然深深的打动了我,除了语言本身(它的实现只部分遵从了这一原则),它的核心哲学依然足够强壮,让我们来看看Paul Graham在“Arc challenge”里的这段话吧:
假设要写一个程序让某个URL(比如,http://localhost:port/said)产生一个带有输入框和提交按钮的页面,然后当提交按钮被按下时,这时应该有第二个页面,这个页面只包含一个简单的链接“点这里”,当你点了这个链接之后,会出现第三个页面,在这个页面你会看到“你刚刚说的是:……”,这里的省略号就是你在第一个页面所输入的内容。
要实现上面描述的功能,下面是Arc的解决方式:
(defop said req (aform [w/link (pr "you said: " (arg _ "foo")) (pr "click here")] (input "foo") (submit)))
学习Arc的一个额外的好处就是你可以顺带了解到Racket语言的神奇,好吧,我承认我作弊帮Racket做宣传了。
更多资源
* Succinctness is Power
* Arc指南
* Arc核心
* Arc论坛
* Arc源码
CoffeeScript
发布日期:2009,作者:Jeremy Ashkenas
我发现Jeremy Ashkenas绝对是个超级聪明的程序员,他的一些哲学与我不谋而合,另外值得注意的是,CoffeeScript是这篇帖子里介绍的这些语言中唯一一个我会在实际工作中使用的语言,它的语法实在是太干净自由了,但是它最牛的地方(也有些人说这是最弱的)就是它只是对JS的非常浅的封装,CoffeeScript实际上是对于Crockford(译者注:JavaScript社区最知名的权威之一,JSON、JSLint、JSMin和ADSafe之父)的“Javascript: The Good Parts”一书的最好诠释,并且还是以更优美的语法实现的。
CoffeeScript最有趣的一个特性就是它提供了一种非常轻量级的JSON语法:
jsn = foo: 'a' bar: 'b' jsn.bar #=> 'b'
这让下面这样的对象语法变得更加容易:
sanders = speed: 8 juke: 10 report: -> "#{@speed} and #{@juke}" sanders.report(); #=> '8 and 10'
还有列表的实现:
transpose = (matrix) -> (t[i] for t in matrix) for i of matrix[0] transpose [[1,2,3],[4,5,6]] //=> [[1,4],[2,5],[3,6]]
下面这点不知道该说好还是坏,CoffeeScript还提供了基于类支持:
class Animal constructor: (voice) -> @voice = voice speak: => "#{@voice}!!" class Dog extends Animal constructor: -> super("ruff") d = new Dog d.speak() #=> 'ruff!!'
CoffeeScript并不是第一个基于Javascript的语言,但是它对JS的适配和支持是最完美的,并且实践证明大多数人都可以接受这种方式,而同样重要的是Coffeescript还解决了寄生语言如何与现有的JS库和框架共存的问题。
更多资源:
* 官方网站
* 源码
* CoffeeScript书籍
--------------
本文是“Programming language development: the past 5 years”一文的上半部分,作者:Fogus,翻译:yuanyiz
1 ::...
或是邮件反馈可也:
askdama[AT]googlegroups.com
订阅 substack 体验古早写作:
关注公众号, 持续获得相关各种嗯哼: