Erlang

维基百科,自由的百科全书
跳转至: 导航搜索
Erlang语言
Erlang logo.png
编程范型 多重典範函數式并行
发行时间 1987年
設計者 喬·阿姆斯特朗
實作者 愛立信
最新发行时间 R16B03 / 2013年12月11日;7個月前 (2013-12-11)
啟發語言 PrologLISP
影響語言 Scala
作業系統 跨平台
網站 http://www.erlang.org/
LYME is Erlang-based

Erlang英语发音:/ˈɜrlæŋ/)是一種通用的并行程序设计语言,它由喬·阿姆斯特朗(Joe Armstrong)在瑞典電信設備製造商愛立信所轄的電腦科學研究室開發,目的是創造一種可以應付大規模開發活動的程序设计语言執行環境。Erlang於1987年釋出正式版本,最早是愛立信擁有的私有軟體,經過十年的發展,於1998年發表開放源碼版本。

Erlang是運作於虛擬機解释型语言,但是現在也包含有烏普薩拉大學高性能Erlang計劃(HiPE)[1]開發的原生程式碼編譯器,自R11B-4版本開始,Erlang也支持脚本方式执行。在程式設計典範上,Erlang屬於多重典範程式語言,涵蓋函數式并行分布式。循序執行的Erlang是一个及早求值, 單次賦值动态类型函數式程式語言

開發及演變歷史[编辑]

Erlang得名於丹麥數學家統計學家Agner Krarup Erlang,同時Erlang還可以表示Ericsson Language。Erlang語言由瑞典愛立信電信公司的喬·阿姆斯特朗開始設計,開始於公元一九八零年代。最初是以Prolog程序设计语言為基礎,幾度改版之後,改成以Joe's Abstract Machine為基礎的獨立語言執行環境。雖然語言風格仍與Prolog相近,不過因Erlang語言設計的走向,Erlang成為具备函數語言特色的程序设计语言[2]

發行版本[编辑]

1998年起,Erlang發布開放源碼版本,稱為開源電信平台開源電信平台採用修改過的Mozilla公共許可證協議發放,同時爱立信仍然提供商業版本的技術支持。目前,Erlang最大的商業用户是爱立信,其他知名用户有北電網路亞瑪遜以及T-Mobile[3]

語言特色[编辑]

  • 并行程序设计 在語言中,可以藉由spawn/*函數,將特定的函數設定為獨立的进程,之後可以做跨进程通訊。
  • 函數式程序設計 由於Erlang早期以Prolog開發製成,受語言特性影響,即成為函數式語言。
  • 單次賦值 每個变量只能跟数据綁一次,所以,不像一般程序设计语言的变量可以多次指定為不同的值。單次賦值的好處是狀態單純,使程序容易閱讀。
  • 及早求值或嚴格求值 Erlang基本求值策略為電腦語言中及早求值之特性。而且,可以藉由明確使用無參數的λ表达式,將特定函數設定為惰性求值策略。
  • 动态数据类型與類型系統 有編譯時期的类型檢查系統支持。
  • 快速失败 在執行時期發生的錯誤,會由錯誤位置送出訊息,發生錯誤的进程立刻停止执行。藉由进程通讯机制,可以自動傳遞錯誤、捕捉錯誤,使其他进程能夠幫助處理錯誤。
  • 代码熱更新 由於Erlang是函數語言,可以撰寫特定的程序结构,製作即時更換新版函數的機制。
  • 腳本語言 Erlang實作提供了腳本執行方式。

語言構成[编辑]

Erlang程序結構以函數定義為主。函數是一組將輸入分別對應到輸出的規則,對應方式遵守數學函數的慣例。此外,Erlang語言由幾項構句要素所組成,包括文字(或稱原子)、數字、列表、值組、字元、字串、二進位資料、模組、與特定用途的關鍵字如fun ... end, if ... end, case ... of ... end, spawn, !, receive ... end等等。以下段落分別列示並舉例說明Erlang程式的基本構成部份,涵蓋資料格式表達式格式內建函數

資料格式[编辑]

類型 意義與構詞規則 例子
原子 原子是基本資料單元,以一般文字構成。構詞規則有:
  1. 以小寫英文字元開頭、不包含空白的連續文字。
  2. 以單引號包含的任意連續文字。
  • hello
  • 'Hello, World!'
  • true
  • a3b
數字 數字是基本資料單元,可以是整數或實數。
  1. 連續數字符號。
  2. 包含一個小數點的連續數字符號,並不以小數點開頭也不以小數點結尾。
  3. 符合前二項原則,並以 + 或 - 符號開頭。
  4. 以#分割的数字,前者将表示进制。
  • 302
  • 3.1416
  • +1
  • -2
  • 16#10
列表 列表是與鏈接序列相同的資料結構。任一列表大致區分為頭部與尾部,頭部是列表的第一項,尾部是列表除第一項之外的其他部份。
  1. 左邊以 [ 、右邊以 ] 符號,包含一串以逗號分隔的零或多項構句要素。
  2. 符合前項原則,當存在任一 | 符號時, | 的左邊有一串逗號分隔的構句要素, | 的右邊只有一個構句要素。
  • []
  • [1,2,3]
  • [ [1],2|[] ]
值組 值組是將二個、三個或多個資料放在一起的資料結構。
  • 左邊以 { 、右邊以 } 符號,包含一串以逗號分隔的零或多項構句要素。
  • {}
  • {{1},2}
字元 Erlang將字元存為32位元的整數。
  1. 任何可見的字元,以 $ 開頭、後接該字元符號,即表示字元本身。
  2. 任何不可見的字元,可使用以 $ 開頭、後接該字元符號的逸出序列表達。
  • $3
  • $)
  • $\012
  • $\x0A
  • $\n
字串 Erlang將字串視同一列整數列表。
  1. 以雙引號包含任意多個文字,即為字串。
  2. 以一列整數列表表達,使其中每個整數項目都落在合理的字元的值範圍,此列也是字串。
  • "Hello, World!"
  • [65,66,67]
二進位資料 以左邊 << 、右邊 >> 符號,包含由位元語法表示的資料。
  • <<"Hello, World!">>
  • <<65:8,66:8,67:8>>
函數識別項 Erlang容許用文字表示函數識別項,使程式中可以對指定函數做函數呼叫,或者當做資料傳遞。函數識別項格式為:
  • fun 函數名稱/參數數目
  • fun a_function/3

用途見以下「函數式程式設計」小節。

程序代號 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 ( 代名 , 資料 ).
  • 使用巨集的語法是:
? 代名
  • Erlang有一些內定語法,例如模組名稱為
?MODULE
  • -define(hello, world).
test() -> ?hello.

表達式格式[编辑]

類型 構詞規則 例子
變數

變數是一種提供與資料綁定、賦值的詞彙。Erlang的變數是單一賦值,一個變數只能賦值一次。

  1. 以大寫英文字元開頭的任意連續文字,是具名變數。
  2. 以 _ 開頭的任意連續文字,是匿名變數,用於變數必須使用、但相對的值可以忽略的場合。
  • Number1
  • _
  • _nothing
樣式匹配
  1. 樣式是指以原子、列表或值組表達的結構,結構中可能包含一些未賦值的變數。
  2. 給二個樣式 A 和 B ,樣式匹配是用 A = B 表示法,表示要讓 A 對 B 匹配。如果匹配成功, A 包含的未賦值變數都會賦值,並且傳回 B 的值。
  • A = 42
  • {ok, Node} = {ok, 'Wikipedia'}
  • [H|T] = [1,2,3]
函數

函數是由一或多項對應規則組成。每一項規則是將一部份匹配樣式的輸入映射到相對的輸出。

  • 規則:格式為
  原子 ( 變數 , 變數 , ... ) -> 表達式 , 表達式 , ...
在 -> 左邊是函數名稱及搭配的參數列,右邊為函數本體。
  • 函數:格式為
  規則 ; 規則 ; ... ; 規則 .
以分號分隔一或多項規則,並最後以句號結束。
同一函數的每一規則必須以相同的原子開頭,並接受相同數量的
參數列。

函數被呼叫時,會讓呼叫方依序對被呼叫方的每一條函數規則做樣式匹配,比對函數名稱、參數數目、參數樣式等等。首先完成匹配的函數規則會被執行,並且後面的函數規則會被忽略。

見以下「函數式程式設計」小節
函數呼叫 格式為
  原子 ( 資料 , 資料 , ... )
表示函數名稱及搭配的參數列。呼叫符合函數名稱及
相同參數數目的函數。

函數呼叫時,所給予的參數可能是已賦值的變數。並且,如果參數是變數,必須是已賦值的變數。

見以下「函數式程式設計」小節
真值比較
  • 比較運算:
== 相等
/= 不相等
=< 小於或等於
< 小於
>= 大於或等於
> 大於
=:= 確實相等
=/= 確實不相等
  • 真值運算:
not
and
or
xor 非此即彼
orelse 或 (捷徑求值)
andalso 且 (捷徑求值)

真值比較的結果,如果成功則傳回true原子,失敗則傳回false原子。

請記得,Erlang是以true和false表示布爾資料類型

(略)
運算子 Erlang提供常用的運算子方便基本運算。運算子是用在中序的表達式裏,包含 + - * / div(商) rem(餘) 等。位元算算有 bnot, band, bor, bxor, bsl(算術左移), bsr(算術右移) 等。用於列表有 ++(列表銜接) --(列表剔除) 等。各種運算式皆可用 ( ) 調整運算優先順序。 (略)
防衛式

防衛式是接在when關鍵字之後的一組表達式,藉由防衛式的真偽值做程式控制處理。 防衛式的原則如下方所述:

  1. 代表true或false的變數或原子,是防衛式。
  2. 任何真值運算式,包括比較算式和邏輯算式,是防衛式。
  3. 傳回true或false的函數呼叫,是防衛式。
  4. 以逗號分隔的多個防衛式,是防衛式。
  • 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])
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])
end.
發送訊息

Erlang容許向程序傳送訊息。使用 ! 關鍵字,格式為:

程序代號 ! 訊息
  • 訊息可以是各種資料格式。訊息資料格式可以是用各種表達式求出的值。
  • Pid = erlang:spawn(
fun() ->
receive
X -> X
end
end)
  • 以上產生一個程序。
  • Pid ! {hello, world}
  • 以上對Pid送出訊息。
列表解析 列表解析,是提供快速建立列表的語法。語法等同於集合建構式。格式為:
  • [ 變數(表達式中的元素) || 變數(表達式中的元素) <- 表達式 , 防衛式 ]
若無防衛條件,列表解析中不寫防衛式。
  • [ X || X <- [1,2,3] ]
運算結果為[1,2,3]

內建函數[编辑]

開源電信平台包括一個Erlang直譯器、一個Erlang編譯器、程序節點通訊協定、CORBA、一個分散式資料庫Mnesia、以及許多程式庫[4]內建函數涵蓋了各種方面的功能,涵蓋了系統命令、資料存取、格式轉換、網路通訊、圖形介面、 ... 等。以下列表介紹幾項常用的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"

函數式程式設計[编辑]

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最主要的特色是平行導向程式設計,強調多程序平行運作,並且以訊息對彼此溝通。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}資料。程序正常結束時,Reasonnormal

另外,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_admnet_kernelslave、... 等模組,做網路通訊[5]

其他程式設計典範[编辑]

惰性求值[编辑]

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.

應用[编辑]

參考資料[编辑]

  1. ^ High Performance Erlang. [2008-04-13]. 
  2. ^ Coders At Work. Book introduction. [2010-08-30]. Coders At Work一書對Joe Armstrong的口述記錄。
  3. ^ Who uses Erlang for product development?. Frequently asked questions about Erlang. [2008-04-13]. 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等
  4. ^ http://en.wikipedia.org/wiki/Open_Telecom_Platform
  5. ^ 參考分散式Erlanghttp://www.erlang.org/doc/reference_manual/distributed.html
  6. ^ ErlangFreeBSDhttps://www.erlang-solutions.com/about/news/erlang-powered-whatsapp-exceeds-200-million-monthly-users

外部鏈接[编辑]