acm queue 9月的杂志的主题是The Concurrency Problem,力推了Erlang这个语言,其中有篇文章简单的介绍了下这个message-oriented语言。

查了下这个名字的读法,正确的读法应该是air-lang,这里元音a的发音和bang中的a一样。

文章中的第一个程序就有点令人费解,主要原因在于Erlang的语法和一般的imperative language差别很大,和functional language比较类似,但是本质上也有很大的不同。

以Java的一个计数程序为例

// A shared counter.
public class Sequence {
    private int nextVal = 0;

    // Retrieve counter and increment.
    public synchronized int getNext() {
        return nextVal++;
    }

    // Re-initialize counter to zero.
    public synchronized void reset() {
        nextVal = 0;
    }
}

这个程序的功能不用多说了,一个同步的计数程序。它的Erlang翻译版的代码为


-module(sequence1).
-export([make_sequence/0, get_next/1, reset/1]).

% Create a new shared counter.
make_sequence() ->
    spawn(fun() -> sequence_loop(0) end).

sequence_loop(N) ->
    receive
        {From, get_next} ->
            From ! {self(), N},
            sequence_loop(N + 1);
        reset ->
            sequence_loop(0)
    end.

% Retrieve counter and increment.
get_next(Sequence) ->
    Sequence ! {self(), get_next},
    receive
        {Sequence, N} -> N
    end.

% Re-initialize counter to zero.
reset(Sequence) ->
    Sequence ! reset.

初看这个程序自然是一头雾水,不过程序的函数式风格味还是很浓的。

前面提到,Erlang是基于message的,或者说message sending机制是包含在语言系统内部的,语法就是 pid ! message

接下来再来分析这个简单的程序。开头两行是模块和函数声明,略去。make_sequence开始这个进程,spawn/1内置函数创建一个新的进程,并返回pid到调用者。

初始时运行的函数是sequence_loop(0),这个函数接收两种信息,用receive表达式声明:如果收到形式是{From, get_next}的信息,就返回当前的N并调用sequence_loop(N+1),这样下一次收到同样的信息时就能返回N+1了;reset则等价于Java版本中的n=0语句。

get_next/1则是发送给pid为Sequence的进程 {self(), get_next} 这样一个信息,上面解释的sequence_loop/1函数收到这个信息后会返回一个 {self(), N} 的tuple给get_next/1,收到这个信息后get_next/1就能返回N这个值了。

最后reset/1函数则是发送给Sequence一个reset信息。

这个简单的程序里能大致窥见一些Erlang的特点,尤其是它基于信息发送的本质。