Erlang
Erlang(/ˈɜːrlæŋ/)是一种通用的函数式。Erlang也可以指Erlang/OTP的通称,开源电信平台(OTP)是Erlang的常用运行环境及一系列标准组件。
![]() | |
多重典范:函数式、 | |
设计者 | 乔·阿姆斯特朗、Robert Virding、Mike Williams |
实作者 | 爱立信 |
1986年 | |
当前版本 |
|
型态系统 | 动态、强 |
许可证 | Apache许可证2.0 (从OTP 18.0开始) Erlang公共许可协议1.1 (早期版本) |
文档扩展名 | .erl .hrl |
网站 | www |
主要实作产品 | |
Erlang | |
启发语言 | |
Prolog, Smalltalk, PLEX,[2] LISP | |
影响语言 | |
Akka, Clojure, Dart, Elixir, F♯, Opa, Oz, Reia, Rust, Scala | |
|

Erlang 运行环境为专有以下要求的系统设计:
Erlang是运作于虚拟机的,但是现在也包含有乌普萨拉大学高性能Erlang计划(HiPE)[3]开发的原生代码编译器,自R11B-4版本开始,Erlang也支持。在编程范型上,Erlang属于多重典范编程语言,涵盖函数式、及。循序运行的Erlang是一个及早求值, 单次赋值和的函数式编程语言。
它由乔·阿姆斯特朗(Joe Armstrong)在瑞典电信设备制造商爱立信所辖的计算机科学研究室开发,目的是创造一种可以应付大规模并发活动的和运行环境。Erlang于1987年发布正式版本,最早是爱立信拥有的私有软件,经过十年的发展,于1998年发表开放源码版本。
开发及演变历史
Erlang得名于丹麦数学家及统计学家Agner Krarup Erlang,同时Erlang还可以表示Ericsson Language。Erlang语言由瑞典爱立信电信公司的乔·阿姆斯特朗开始设计,开始于公元一九八零年代。最初是以Prolog为基础,几度改版之后,改成以Joe's Abstract Machine为基础的独立语言运行环境。虽然语言风格仍与Prolog相近,不过因Erlang语言设计的走向,Erlang成为具备函数语言特色的[4]。
发行版本
1998年起,Erlang发布开放源码版本,称为开源电信平台。开源电信平台采用修改过的Mozilla公共许可证协议发放,同时爱立信仍然提供商业版本的技术支持。目前,Erlang最大的商业用户是爱立信,其他知名用户有北电网络、以及T-Mobile等[5]。
语言特色
- 在语言中,可以借由spawn/*函数,将特定的函数设置为独立的,之后可以做跨通信。
- 函数式设计 由于Erlang早期以Prolog开发制成,受语言特性影响,即成为函数式语言。
- 单次赋值 每个只能跟绑一次,所以,不像一般的可以多次指定为不同的值。单次赋值的好处是状态单纯,使容易阅读。
- 及早求值或严格求值 Erlang基本求值策略为电脑语言中及早求值之特性。而且,可以借由明确使用无参数的,将特定函数设置为惰性求值策略。
- 与类型系统 有编译时期的检查系统。
- 在运行时期发生的错误,会由错误位置送出消息,发生错误的立刻停止。借由,可以自动传递错误、捕捉错误,使其他能够帮助处理错误。
- 热更新 由于Erlang是函数语言,可以撰写特定的,制作即时更换新版函数的机制。
- 脚本语言 Erlang实作提供了脚本运行方式。
语言构成
Erlang结构以函数定义为主。函数是一组将输入分别对应到输出的规则,对应方式遵守数学函数的惯例。此外,Erlang语言由几项构句要素所组成,包括文本(或称原子)、数字、列表、值组、字符、字符串、二进位数据、模块、与特定用途的关键字如fun ... end, if ... end, case ... of ... end, spawn, !, receive ... end等等。以下段落分别列示并举例说明Erlang程序的基本构成部份,涵盖数据格式、表达式格式与内置函数。
数据格式
类型 | 意义与构词规则 | 例子 |
---|---|---|
原子 | 原子是基本数据单元,以一般文本构成。构词规则有:
|
|
数字 | 数字是基本数据单元,可以是整数或实数。
|
|
列表 | 列表是与链接串行相同的数据结构。任一列表大致区分为头部与尾部,头部是列表的第一项,尾部是列表除第一项之外的其他部份。
|
|
值组 | 值组是将二个、三个或多个数据放在一起的数据结构。
|
|
字符 | Erlang将字符存为32比特的整数。
|
|
字符串 | Erlang将字符串视同一列整数列表。
|
|
二进位数据 | 以左边 << 、右边 >> 符号,包含由比特语法(页面存档备份,存于)表示的数据。 |
|
函数识别项 | Erlang容许用文本表示函数识别项,使程序中可以对指定函数做函数调用,或者当做数据传递。函数识别项格式为:
|
用途见以下「函数式编程」小节。 |
进程代号 | Erlang容许以内置函数erlang:spawn/3、erlang:spawn/4、erlang:spawn/1、erlang:spawn/2等等,将指定函数启动为一个进程。进程启动之后,Erlang以左边 < 、右边 > ,包含一个数字和点号组成的编号,表示此进程代号。 | 见以下「平行式编程」小节。 |
模块 | Erlang容许将一些程序整理为一个模块。模块的设置,是在源码文件开头书写模块标记,格式为:
-module(模块名称).
-export( [ 函数名称/参数数目 , 函数名称/参数数目 , ... ] ).
-import( 模块名称, [ 函数名称/参数数目 , 函数名称/参数数目 , ... ] ).
模块名称和函数名称都是原子。 -module(模块名称) 定义模块的名字,要与文件名相同。 -export( ... ) 定义模块发布的函数,模块内的任何函数必须要发布才能让外部通过模块调用该函数。 -import( ... ) 定义本模块要从其他模块导入哪些函数,以便本模块自己使用。另外,为了方便程序的撰写并测试,还容许 -compile(export_all) 定义本模块的所有函数全部对外发布。 -compile(export_all). |
(略) |
宏 | 宏是将一项数据以另一个文本做为代名。
-define ( 代名 , 数据 ).
? 代名
?MODULE |
|
表达式格式
类型 | 构词规则 | 例子 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
变量 |
变量是一种提供与数据绑定、赋值的词汇。Erlang的变量是单一赋值,一个变量只能赋值一次。
|
| |||||||||||||||
样式匹配 |
|
| |||||||||||||||
函数 |
函数是由一或多项对应规则组成。每一项规则是将一部份匹配样式的输入映射到相对的输出。
原子 ( 变量 , 变量 , ... ) -> 表达式 , 表达式 , ...
在 -> 左边是函数名称及搭配的参数表,右边为函数本体。
规则 ; 规则 ; ... ; 规则 .
以分号分隔一或多项规则,并最后以句号结束。
同一函数的每一规则必须以相同的原子开头,并接受相同数量的
参数表。
函数被调用时,会让调用方依序对被调用方的每一条函数规则做样式匹配,比对函数名称、参数数目、参数样式等等。首先完成匹配的函数规则会被运行,并且后面的函数规则会被忽略。 |
见以下「函数式编程」小节 | |||||||||||||||
函数调用 | 格式为
原子 ( 数据 , 数据 , ... )
表示函数名称及搭配的参数表。调用符合函数名称及
相同参数数目的函数。
函数调用时,所给予的参数可能是已赋值的变量。并且,如果参数是变量,必须是已赋值的变量。 |
见以下「函数式编程」小节 | |||||||||||||||
真值比较 |
:{|
| ||||||||||||||||
not | 非 | ||||||||||||||||
and | 且 | ||||||||||||||||
or | 或 | ||||||||||||||||
xor | 非此即彼 | ||||||||||||||||
orelse | 或 (捷径求值) | ||||||||||||||||
andalso | 且 (捷径求值) |
真值比较的结果,如果成功则传回true原子,失败则传回false原子。
请记得,Erlang是以true和false表示布尔数据类型。 | (略) |- | 操作符 | Erlang提供常用的操作符方便基本运算。操作符是用在中序的表达式里,包含 + - * / div(商) rem(余) 等。比特算算有 bnot, band, bor, bxor, bsl(算术左移), bsr(算术右移) 等。用于列表有 ++(列表衔接) --(列表剔除) 等。各种表达式皆可用 ( ) 调整运算优先级。 | (略) |- | 防卫式(页面存档备份,存于) | 防卫式是接在when关键字之后的一组表达式,借由防卫式的真伪值做程序控制处理。 防卫式的原则如下方所述:
- 代表true或false的变量或原子,是防卫式。
- 任何真值表达式,包括比较算式和逻辑算式,是防卫式。
- 传回true或false的函数调用,是防卫式。
- 以逗号分隔的多个防卫式,是防卫式。
|
- false
- A =< 10
- erlang:is_number(N), erlang:is_atom(A)
|- | 受防卫式限制的函数 | 函数对应规则格式为:
原子 ( 变量 , 变量 , ... ) -> 表达式 , 表达式 , ...
若一条函数规则加上防卫式,此规则的处理范围会多一些限制。受防卫式限制的函数对应规则格式为:
原子 ( 变量 , 变量 , ... ) when 防卫式 -> 表达式 , 表达式 , ...
|
- atom_pair(A, B) when is_atom(A), is_atom(B) -> {A, B}.
|- | 行后注解 | 任何 % 符号开头,往后到行尾的文本皆为注解文本。 | 'H.W.'. % Hello, World! |- | λ演算式 | λ演算式是匿名函数,在Erlang以 fun ... end 关键字叙述。格式为:
fun ( 变量 , 变量 , ... ) -> 表达式 , 表达式 , ... end
使用无参数的λ演算式,可以做出惰性求值的效果。 |
- (fun(X)->X>0 end)(1).
- % (λ x . x > 0) 1
- lists:takewhile(
- fun(X)->
- X>0 and X=<10 end,
- [1,5,11]).
|- | 因果式 | 使用 if ... end 关键字叙述条件判断原则。格式为:
if 防卫式 -> 表达式, 表达式, ... ;
防卫式 -> 表达式, 表达式, ... ;
......
防卫式 -> 表达式, 表达式, ...
end
|
- parse(A) ->
- if
- is_number(A),
- round(A) == A,
- A >= 0 ->
- {natural, A};
- is_number(A) ->
- {real, A};
- is_atom(A) ->
- {word, A};
- true ->
- {unknown, A}
- end.
|- | 案例式 | 使用 case ... of ... end 关键字,根据一个变量的案例,带往相对的处理进程。格式为:
case 表达式 of
样式 -> 表达式, 表达式, ... ;
样式 -> 表达式, 表达式, ... ;
......
样式 -> 表达式, 表达式, ...
end
- 样式之后可接when防卫式。
|
- show(A) ->
- case A of
- {natural, N} ->
- io:format("Natural number ~.10B is met.~n", [N]);
- {real, R} ->
- io:format("Real number ~f is met.~n", [R]);
- {word, W} ->
- io:format("\"~w\" is met.~n", [W]);
- {unknown, U} ->
- io:format("Unknown structure ~w.~n", [U])
- {natural, N} ->
- end.
|- | 试误 | 使用 try ... catch ... end 关键字叙述试误的情况与结果。格式为:
try 表达式 of
样式 -> 表达式, 表达式, ... ;
样式 -> 表达式, 表达式, ... ;
......
样式 -> 表达式, 表达式, ...
catch
样式(例外) -> 表达式, 表达式, ... ;
样式(例外) -> 表达式, 表达式, ... ;
......
样式(例外) -> 表达式, 表达式, ...
after
表达式, 表达式, ...
end
- 不需要使用after段落时,可省略after段落。
- 样式之后可接when防卫式。
| (略) |- | 接收消息 | 每个Erlang程序运行时,都可以从自己进程的邮箱中取得由其他进程送到的消息。可以使用 receive ... end 关键字接收消息,格式为:
receive
样式 -> 表达式, 表达式, ... ;
样式 -> 表达式, 表达式, ... ;
......
样式 -> 表达式, 表达式, ...
end
- 样式之后可接when防卫式。
|
- loop(FromPid, Result) ->
- receive
- {FromPid, stop} ->
- Result;
- {FromPid, Any} ->
- loop(FromPid, [Any|Result])
- {FromPid, stop} ->
- end.
|- | 发送消息 | Erlang容许向进程发送消息。使用 ! 关键字,格式为:
进程代号 ! 消息
- 消息可以是各种数据格式。消息数据格式可以是用各种表达式求出的值。
|
- Pid = erlang:spawn(
- fun() ->
- receive
- X -> X
- end
- receive
- end)
- 以上产生一个进程。
- Pid ! {hello, world}
- 以上对Pid送出消息。
|- | 列表解析(页面存档备份,存于) | 列表解析,是提供快速创建列表的语法。语法等同于集合建构式(页面存档备份,存于)。格式为:
- [ 变量(表达式中的元素) || 变量(表达式中的元素) <- 表达式 , 防卫式 ]
- 若无防卫条件,列表解析中不写防卫式。
|
- [ X || X <- [1,2,3] ]
- 运算结果为[1,2,3]
|}
内置函数
开源电信平台包括一个Erlang解释器、一个Erlang编译器、进程节点通信协定、CORBA、一个分布式数据库Mnesia(页面存档备份,存于)、以及许多程序库[6]。 内置函数涵盖了各种方面的功能,涵盖了系统命令、数据访问、格式转换、网络通信、图形接口、 ... 等。以下列表介绍几项常用的Erlang内置函数。(参阅文档(页面存档备份,存于)或索引 (页面存档备份,存于))
模块:函数名称 / 参数数目 | 用途 |
---|---|
c:cd / 1 |
切换到指定目录位置。 > c:cd("D:\\code").
D:/code/
ok
当指定目录不正确时,则保持在原目录位置。 |
c:c / 1 |
编译指定的代码,之后加载新编译好的程序。 > c:c(test). % test.erl 必须存在于目录位置
{ok, test}
> c:c(test1).
./test1.erl:none: ...
error |
io:format / 2 |
按照指定的格式文本将数据印在标准输出端口。 > io:format("~.8B, ~c, ~s, ~.2f~n", [32, $a, "hello", 3.1416]).
40, a, hello, 3.14
ok |
lists:sublist / 3 |
由列表中截取子列表。Erlang字符串是整数列表,于是本函数视同截取子字符串。 > lists:sublist("Hello, World!", 2, 2).
"el" |
Hello World 程序
这是输出 Hello World 的一种方式:[7]
-module(hello).
-export([hello_world/0]).
hello_world() -> io:fwrite("hello, world\n").
若要编译这个程序,将它存为一个名为 hello.erl 的文本档,然后从 Erlang终端 进行编译。不要忘了在每个命令的最后加上一个句号(.)。例如:
Erlang (BEAM) emulator version 4.9.1 [source]
Eshell V4.9.1 (abort with ^G)
1> c(hello).
{ok,hello}
(在 Unix系统 上,你可以通过在命令行里输入 "erl" 来进入 Erlang终端。在 Windows系统 上,你需要打开一个 命令提示符 窗口,然后输入 "werl"来进入 Erlang终端,或者在程序功能表中找到 Erlang 的图标。)从 Erlang终端 上运行这个程序:
2> hello:hello_world().
hello, world
ok
函数式编程
Erlang支持函数式编程的一般特色,特色包括单次赋值、递归定义、λ演算与高端函数等等。Erlang函数大致写法如下,以整数阶乘模块为例:
-module(fact).
-export([fac/1]).
fac(N) when N > 1 ->
N * fac(N-1);
fac(1) ->
1.
以下是快速排序算法的Erlang实作:
%% quicksort:qsort(List)
%% Sort a list of items
-module(quicksort).
-export([qsort/1]).
qsort([]) -> [];
qsort([Pivot|Rest]) ->
qsort([ X || X <- Rest, X =< Pivot]) ++ [Pivot] ++ qsort([ Y || Y <- Rest, Y > Pivot]).
以下是费氏数列求解函数:
-module(example).
-export([fibo/1]).
fibo(N) when N > 1 ->
fibo(N-1) + fibo(N-2);
fibo(1) ->
1;
fibo(0) ->
0.
> c(example).
{ok,example}
> lists:map(fun(X)->example:fibo(X) end, lists:seq(1,10)).
[1,1,2,3,5,8,13,21,34,55]
函数式编程难免以递归计算,而消耗了大量递归堆栈空间。为了克服这个问题,一般使用累积参数与尾端递归等技巧节省递归数目:如以下例子。
-module(test).
-export([fibo_accu/1]).
fibo_accu(N) ->
fibo(N, 0, 1).
fibo(N, C1, C2) when N > 2 ->
fibo(N-1, C2, C1+C2);
fibo(0, _, _) ->
0;
fibo(1, _, _) ->
1;
fibo(_, C1, C2) ->
C1+C2.
> c(example).
{ok,test}
> lists:map(fun(X)->test:fibo_accu(X) end, lists:seq(1,10)).
[1,1,2,3,5,8,13,21,34,55]
函数式编程容许使用高端函数求解。以下例子说明Erlang实做复合函数。 ( f o g ,念作 f after g 。)
'After'(F, G) ->
fun(X) ->
erlang:apply(F, [erlang:apply(G, [X])])
end.
- 请注意after是Erlang关键字。因此,以上函数命名为′After′避开关键字。
> (example:'After'(fun test:show/1, fun test:parse/1))(3.1416).
Real number 3.141600 is met.
ok
平行式编程
Erlang最主要的特色是平行导向编程,强调多进程平行运作,并且以消息对彼此沟通[8]。Erlang提供了spawn函数和 ! 、 receive ... end 等关键字,可以描述在Erlang/开源电信平台中的如何启动一些进程、并且如何让进程传递消息。此外,平行导向编程的精神还强调进程的容错处理,借由进程发生错误时的消息传递,使其他进程可以得知错误的发生,使方便于后续处理。以下分别介绍平行导向编程的一般程序撰写方式,以及错误处理的使用方式。
平行导向编程
基本的平行程序示范如下:
- 以下启动一个进程。
% create process and call the function web:start_server(Port, MaxConnections)
ServerProcess = spawn(web, start_server, [Port, MaxConnections]),
- 以下是在任何程序中,对先前起动的进程送一则消息 {pause, 10} 。
% send the {pause, 10} message (a tuple with an atom "pause" and a number "10")
% to ServerProcess (asynchronously)
ServerProcess ! {pause, 10},
- 以下是一段接收消息的程序。每个进程都拥有一份邮箱,可伫留收到的消息; receive ... end 程序片断是从进程的邮箱中取出最早伫留的消息。
% receive messages sent to this process
receive
a_message -> do_something;
{data, DataContent} -> handle(DataContent);
{hello, Text} -> io:format("Got hello message: ~s", [Text]);
{goodbye, Text} -> io:format("Got goodbye message: ~s", [Text])
end.
收到 a_message 结果就是 do_something ;收到 {data, DataContent} 结果会调用 handle(DataContent) ;
收到 {hello, Text} 结果教是印出 "Got hello message: ..." ,收到 {goodbye, Text} 结果是印出
"Got goodbye message: ..." 。
以下程序,示范产生一组环状传递消息的进程。
ring_proc(Funs) ->
Ns = lists:seq(1, length(Funs)),
[P|Pids] = [ spawn(?MODULE, lists:nth(Nth,Funs),[]) || Nth <- Ns ],
[ Pid ! ToPid || {Pid, ToPid} <- lists:zip([P|Pids], Pids++[P]) ].
func() ->
receive
ToPid ->
func_msg_(ToPid)
end.
func_msg_(ToPid) ->
receive
stop ->
io:format("Stop process ~w~n", [self()]),
ToPid ! stop;
Message ->
io:format("~w: transmit message to ~w~n", [self(), ToPid]),
ToPid ! Message,
func_msg_(ToPid)
end.
接收stop消息,就对下一个进程送stop消息;接收到其他任何消息,就对下一个进程送同样的消息。
如果发送任何其他消息,就会让所有的进程不断对下一个进程传递消息。而以下是测试发送stop消息的运行结果。
> [P|_] = example:ring_proc([func,func,func]).
[<0.233.0>,<0.234.0>,<0.232.0>]
> P ! stop.
Stop process <0.233.0>
stop
Stop process <0.234.0>
> Stop process <0.232.0>
>
容错处理
Erlang容错处理机制,由二个步骤实现:一是将二个进程连接起来,二者之间存在一道通信管道,可提供错误消息的传递 ── 在此使用link/1函数;二是将进程回报错误的机制打开 ── 在此使用process_flag/2函数。
- 使用link(Pid)让进程连接到另一个进程。
-module(example).
-compile(export_all).
hello() ->
Pid = spawn(?MODULE, world, []),
link(Pid),
... .
运行时,以 Pid = spawn(example, hello, []) 启动进程,此进程将启动另一个进程,并且与它连接。
- 但以上程序还不会有错误消息的传递机制,因为回报错误的开关还没有打开。
- 打开进程回报错误机制。
以上 hello/0 函数前段使用process_flag/2函数,将trap_exit标签打开,即可打开进程回报错误机制。
hello() ->
process_flag(trap_exit, true),
Pid = spawn(?MODULE, world, []),
link(Pid),
... .
于是,当进程结束时,会送出{'EXIT', From, Reason}数据。进程正常结束时,Reason为normal。
另外,spawn函数另外有进程连接版本,spawn_link函数,同时启动并连接到新进程。
分布式编程
Erlang提供分布式机制,能在另一台电脑启动一些Erlang进程,并由本机电脑对其他电脑的Erlang进程传递消息。
- 当启动Erlang环境时,加上一个网络节点名称,就进入分布式Erlang模式。节点可以使用端口号与其他节点通信。
$> erl -name node_1
- 在同一个网域中,网络节点名称可以使用短名。
$> erl -sname node_1
启动新的网络节点时,Erlang使用epmd (Erlang端口号对应管理系统) 指派端口号,提供节点使用。
当知道一个网络节点名称时,可以在该节点产生新进程。
- 在指定节点RemoteNode启动一个进程,spawn启动参数依序为节点名称、模块名称、函数名称、函数的参数表。
% create a remote process and call the function web:start_server(Port, MaxConnections)
% on machine RemoteNode
RemoteProcess = spawn(RemoteNode, web, start_server, [Port, MaxConnections]),
在远程节点产生新进程之后,可以使用平行式编程的技巧,与远程进程通信。
Erlang / 开源电信平台提供的程序库,于分布式编程可以使用net_adm、net_kernel、slave、... 等模块,做网络通信[9]。
其他编程典范
惰性求值
Erlang程序员可以使用惰性求值。不过,必须使用λ演算式,才能做到惰性求值。
以下是惰性求值的一例:假设有个剖析器程序如下,由于及早求值特征,本程序将不会求解。
expr() -> alt(then(factor(), then(literal($+), factor())),
then(factor(), then(literal($-), factor()))).
factor() -> alt(then(term(), then(literal($*), term())),
then(term(), then(literal($/), term()))).
term() -> alt(number(),
xthen(literal($(), thenx(expr(), literal($))))).
此处使用λ演算式及适当使用函数名称表示,就能进行求值。示例如下。
expr() ->
fun () ->
alt(then(fun factor/0, then(literal($+), fun factor/0)),
then(fun factor/0, then(literal($-), fun factor/0)))
end.
factor() ->
fun () ->
alt(then(fun term/0, then(literal($*), fun term/0)),
then(fun term/0, then(literal($/), fun term/0)))
end.
term() ->
fun () ->
alt(number(),
xthen(literal($(), thenx(expr(), literal($)))))
end.
应用
- Wings 3D,一个用Erlang编写的三维计算机图形软件。
- YAWS(页面存档备份,存于),以Erlang编写的高效HTTP服务器。
- DISCO(页面存档备份,存于),以Erlang编写的MapReduce架构系统。
- Apache CouchDB(页面存档备份,存于),以Erlang编写的MapReduce文档式数据库系统。
- RabbitMQ(页面存档备份,存于),能搭配Erlang运作的消息队列系统。
- 开放电信平台
- WhatsApp:其后端服务器应用使用了Erlang及FreeBSD[10]。支持了4.5亿的活跃用户
- ejabberd(页面存档备份,存于),世界上最流行的XMPP即时通讯服务器
- EMQX(页面存档备份,存于),以Erlang编写的高可用、分布式MQTT消息服务器。
社区
- Erlang Central(英文)
- Erlang Resources 豆瓣小站(页面存档备份,存于)(简体中文)
- Erlang中文社区 erlang-china.org(简体中文)
- Erlang中文教程 erlang-cn.com(页面存档备份,存于)(简体中文)
- Erlang中文社区 cnerlang.com(简体中文)
- Erlang中文 erlang-cn.org(简体中文)
参考数据
- . 2024年3月7日 [2024年3月20日].
- . [2018-05-05]. (原始内容存档于2017-07-15).
- . [2008-04-13]. (原始内容存档于2011-06-16).
- . Book introduction. [2010-08-30]. (原始内容存档于2010-03-05).见Coders At Work一书对Joe Armstrong的口述记录。
- . Frequently asked questions about Erlang. [2008-04-13]. (原始内容存档于2008-04-19). “The largest user of Erlang is Ericsson. Ericsson use it to write software used in telecommunications systems. Many (dozens) projects have used it, a particularly large one is the extremely scalable AXD301 ATM switch.” FAQ中列出的其他用户包括: Nortel、Deutsche Flugsicherung、T-Mobile等
- . [2010-09-03]. (原始内容存档于2011-05-12).
- 译自官网 http://www.erlang.org/faq/getting_started.html (页面存档备份,存于)
- Armstrong, Joe. . Communications of the ACM. September 2010, 53 (9): 68–75. doi:10.1145/1810891.1810910.
Erlang is conceptually similar to the occam programming language, though it recasts the ideas of CSP in a functional framework and uses asynchronous message passing.
- 参考分布式Erlang (页面存档备份,存于), http://www.erlang.org/doc/reference_manual/distributed.html (页面存档备份,存于)
- Erlang及FreeBSD. [2014-02-22]. (原始内容存档于2014-02-25).
延伸阅读
- Armstrong, Joe. (PDF). Ph.D. Dissertation. The Royal Institute of Technology, Stockholm, Sweden. 2003 [2016-02-13]. (原始内容存档 (PDF)于2015-03-23).
|url-status=
和|dead-url=
只需其一 (帮助) - Armstrong, Joe. . . 2007: 6–1. ISBN 978-1-59593-766-7. doi:10.1145/1238844.1238850.
- Early history of Erlang(页面存档备份,存于) by Bjarne Däcker
- Mattsson, H.; Nilsson, H.; Wikstrom, C. . First International Workshop on Practical Aspects of Declarative Languages (PADL '99). 1999: 152–163.
- Armstrong, Joe; Virding, Robert; Williams, Mike; Wikstrom, Claes. 2nd. Prentice Hall. 1996-01-16: 358 [2019-10-16]. ISBN 978-0-13-508301-7. (原始内容存档于2012-03-06).
- Armstrong, Joe.
1st. Pragmatic Bookshelf. 2007-07-11: 536. ISBN 978-1-934356-00-5.
- Thompson, Simon J.; Cesarini, Francesco. 1st. Sebastopol, California: O'Reilly Media, Inc. 2009-06-19: 496 [2020-01-20]. ISBN 978-0-596-51818-9. (原始内容存档于2019-10-16).
- Logan, Martin; Merritt, Eric; Carlsson, Richard. 1st. Greenwich, CT: Manning Publications. 2010-05-28: 500. ISBN 978-1-933988-78-8.
- Martin, Brown. . developerWorks. IBM. 2011-05-10 [2011-05-10]. (原始内容存档于2019-10-16).
- Martin, Brown. . developerWorks. IBM. 2011-05-17 [2011-05-17]. (原始内容存档于2019-10-16).
- Wiger, Ulf. (PDF). FEmSYS 2001 Deployment on distributed architectures. Ericsson Telecom AB. 2001-03-30 [2014-09-16]. (原始内容存档 (PDF)于2019-08-19).
外部链接
- Erlang开放源码版本(页面存档备份,存于)(英文)
- Erlang爱立信授权版本(页面存档备份,存于)(英文)
- 因应软件错误建构可靠的分布式系统(页面存档备份,存于) (页面存档备份,存于)(英文)
- 开放式目录计划中和Erlang相关的内容
- Erlang教学(页面存档备份,存于)