Erlang（/ˈɜːrlæŋ/）是一種通用的平行導向函數式程式語言。Erlang 也可以指 Erlang/OTP 的通稱，開源電信平台（OTP）是 Erlang 的常用執行環境及一系列標準元件。

Erlang 執行環境為專有以下要求的系統設計：


* 分散式運算

* 高故障容許度

* 軟性即時運算

* 高可用性、不停運作的應用

* 熱插拔，可以修改程式而不必停機

Erlang 是運作於虛擬機的直譯式語言，但是現在也包含有烏普薩拉大學高效能 Erlang 計劃（HiPE）開發的原生程式碼編譯器，自 R11B-4 版本開始，Erlang 也支援腳本直譯器。在編程範型上，Erlang 屬於多重典範程式語言，涵蓋函數式、平行式及分散式。循序執行的 Erlang 是一個及早求值，單次賦值和動態資料形態的函數式程式語言。

它由喬・阿姆斯特朗（Joe Armstrong）在瑞典電信裝置製造商愛立信所轄的電腦科學研究室開發，目的是創造一種可以應付大規模並發活動的程式語言和執行環境。Erlang 於 1987 年釋出正式版本，最早是愛立信擁有的私有軟體，經過十年的發展，於 1998 年發表開放原始碼版本。



開發及演變歷史

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

發行版本

1998 年起，Erlang 發布開放原始碼版本，稱為開源電信平台。開源電信平台採用修改過的 Mozilla 公共許可證協定發放，同時愛立信仍然提供商業版本的技術支援。目前，Erlang 最大的商業使用者是愛立信，其他知名使用者有北電網路、亞瑪遜以及 T-Mobile 等。

語言特色


* 平行導向程式設計 在語言中，可以藉由 spawn/\
* 函式，將特定的函式設定為獨立的行程，之後可以做跨行程通訊。

* 函數式程式設計 由於 Erlang 早期以 Prolog 開發製成，受語言特性影響，即成為函數式語言。

* 單次賦值 每個變數只能跟資料綁一次，所以，不像一般程式語言的變數可以多次指定為不同的值。單次賦值的好處是狀態單純，使程式容易閱讀。

* 及早求值或嚴格求值 Erlang 基本求值策略為電腦語言中及早求值之特性。而且，可以藉由明確使用無參數的 λ 演算式，將特定函式設定為惰性求值策略。

* 動態資料型態與類型系統 有編譯時期的型態檢查系統支援。

* 錯誤先發 在執行時期發生的錯誤，會由錯誤位置送出訊息，發生錯誤的行程立刻停止動作。藉由行程鏈通機制，可以自動傳遞錯誤、捕捉錯誤，使其他行程能夠幫助處理錯誤。

* 程式碼熱更新 由於 Erlang 是函式語言，可以撰寫特定的程式結構，製作即時更換新版函式的機制。

* 手稿語言 Erlang 實作提供了指令碼執行方式。



語言構成

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

資料格式

表達式格式

內建函式

開源電信平台包括一個 Erlang 直譯器、一個 Erlang 編譯器、程式節點通訊協定、CORBA、一個分散式資料庫 Mnesia（頁面存檔備份，存於網際網路檔案館）、以及許多程式庫。內建函式涵蓋了各種方面的功能，涵蓋了系統命令、資料存取、格式轉換、網路通訊、圖形介面、 ... 等。以下列表介紹幾項常用的 Erlang 內建函式。(參閱檔案（頁面存檔備份，存於網際網路檔案館）或索引 （頁面存檔備份，存於網際網路檔案館）)



Hello World 程式

這是輸出 Hello World 的一種方式：

若要編譯這個程式，將它存為一個名為 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 最主要的特色是平行導向程式設計，強調多程式平行運作，並且以訊息對彼此溝通。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_、... 等模組，做網路通訊。



其他程式設計典範

惰性求值

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。支援了 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（簡體中文）



參考資料



延伸閱讀



外部連結


* Erlang 開放原始碼版本（頁面存檔備份，存於網際網路檔案館）（英文）

* Erlang 愛立信授權版本（頁面存檔備份，存於網際網路檔案館）（英文）

* 因應軟體錯誤建構可靠的分散式系統（頁面存檔備份，存於網際網路檔案館） （頁面存檔備份，存於網際網路檔案館）（英文）

* 開放式目錄計劃中和 Erlang 相關的內容

* Erlang 教學（頁面存檔備份，存於網際網路檔案館）