β

相见恨晚的 Erlang

Arthur的博客 27 阅读

每隔一定时间,我总会接触一门新的语言。Erlang 算是一门很古老的语言了,对我却是一门新的语言。稍微看了一些,还没实际写过代码。这门语言给我的感觉非常不错,真是有点相见恨晚!

Erlang 是一门函数式语言,状态不可变。在这一点相比 lisp,属于更加严格偏向 haskell 的那一派。当然函数式语言共同的优点都是一致的。虽然很多人谈到 Erlang 的特点就只联想到 Actor 模型,其实呢,函数式范式这一点,也是很有特色的(这也不可避免地导致了这门语言的小众)。

语法方面。Erlang 受到了 Prolog 较大影响,它的 list 是写作 [a, b, c] 这样子的。然而 Shen 语言也是受了到 Prolog 影响的,接触过 Shen 之后再接触到 Erlang,这就让我有一种很熟习的亲切感了。Erlang 里面变量和符号也是用的类似的约定,用大小表示变量,小写表示 atom。写一个最简单的 Erlang 代码,大概长这样子:

fact(0) -> 1;
fact(N) -> N * fact(N-1).

Erlang 有强大的模式匹配,在试过 Shen 语言之后,觉得模式匹配太好用了,支持模式匹配会让代码清爽很多。scheme 之类的没有在语言内置,用各种库和宏的方式来提供,是有点不好的。

数据结构方面,只有 list 和 tuple 两种。这跟 lisp 的哲学很类似,语言也是受了 lisp 那边一些影响的。record 可以通过 tuple 模拟出来,就有点类似 lisp 里面使用宏。Erlang 是 lisp2 的。看过了那么多之后,对于 lisp1 还是 lisp2 早已不那么纠结了。无论 lisp1 或者 lisp2,我都不太介意。

类型系统。Erlang 是动态类型语言,不会像 haskell 或者 ml 那个流派的做法,没有强制要求类型安全,而是更加倾向于 lisp。这也很对我的味口。值得一提的是,我 之前的一些思考 ,认为给 lisp 这类动态语言实现类型的正确做法,Erlang 所采用的正是其中一个方向。Erlang 允许子类型,比较弱化的类型系统,类型只是一种约束,检查代码安全的手段。

Actor 模型。在并发编程,算是为数不多的几个靠谱的做法。Go 使用的 CSP,而 Erlang 使用的 Actor。在 Actor 里面是每个 Process 都绑定了一个邮箱,然后每个 Process 都可以往其它的邮箱里面发消息,这就强制使用异步的操作模式。用 Go 可以很容易模拟也 Erlang 这套行为,而反之不行,说明 Go 的灵活性更好一点。在 Go 里面指针,内存这些都没有隔离,并且还可以回到锁的那一套机制。Erlang 是函数式的无状态,更加纯粹一点。

库和生态,这才是真正让我觉得相见恨晚的理由!我没有看到哪个函数式语言,在工业上或者说工程上能够比较靠谱的。要么都是太学术了,只是教学型语言。要么太小众了,库和生态都不行。捣腾来捣腾去,除了写写玩具的解释器或者编译器,啥都干不了。OTP 有那么多的代码,资源都很完善。自己实现一门语言,就那么几块:编译器,运行时,以及标准库。最难搞的就是库的生态,这个东西靠一个人的力量根本弄不来。最后都只是自娱自乐。就拿 chez 编译器说,这个性能真的牛逼的一踏糊涂,但是库和生态不行。

说说 Erlang 用的虚拟机,是一个叫做 beam 的东西,跟 JVM 扮演的角色差不多。beam 据说是基于 WAM (warren abstract machine) 的,我稍微去了解了一点点 WAM,它其实是一个方便做逻辑编程的虚拟机,是给 prolog 用的。而 Erlang 跟 prolog 的编程模式已经相去甚远了,所以我怀疑实际上这里面可能魔改得有点多。有趣的信息是 beam 虚拟机是一个基于寄存器的虚拟机。另外,beam 是可以编译到原生指令来优化性能的,有一个 HiPE 的项目做这个,目前已经默认包含在官方里面了。

runtime 方面的东西,目前了解得还不深入。不过我觉得可玩性要比 Go 高很多。主要是有虚拟机这一层,天然地把一些问题给分层了。就比如说,Go 的 goroutine 就要考虑分段栈的东西,而到了 Erlang 里面,每个 Process 虚拟机绑定自己的内存区域就可以了。垃圾回收也有影响,由于 Process 天然隔离了,所以 Erlang 里面每个 Process 可以自己做自己的 GC 工作,不影响全局。而 Go 的是全局的 GC,要获取低延迟就要投入更多的优化了。还有在低延迟以及软实时在调度层面的考量,Erlang 也是更加重视的。每个 Process 每次可能运行一定的指令数,过了就会被切换走了,而 Go 是在函数调用时才有机会触发切换,非抢占式的。

最后说说好玩的。一个之前的同事,就基于 Erlang 的生态系统,做了一个 kapok 语言 。Erlang 的编译设计分层很好,它定义了一个 Core Erlang 层。Core Erlang 是比较类似于 lisp 的。在这上面可以做一些工作。kapok 也是一个 lisp,我看它好像更多的是建立在 Erlang 的 AST 上面的。而我受 Shen 语言的影响多一点,觉得可以在 Core Erlang 之上,先做一个类似 Shen 语言里面 klambda 那一层。也就是,把 Erlang 的生态当作 lisp 的 runtime 使用,来构建 klambda 语言。然而再在 klambda 之上,去构造自己想要的语言。

作者:Arthur的博客
原文地址:相见恨晚的 Erlang, 感谢原作者分享。

发表评论