1. 程式人生 > >1.1 Erlang教程-序列程式設計

1.1 Erlang教程-序列程式設計

程式1.1用於計算整數的階乘:
程式1.1

-module(math1).
-export([factorial/1]).
factorial(0) -> 1;
factorial(N) -> N * factorial(N - 1).

函式可以通過shell 程式進行互動式求值。 Shell會提示輸入一個表示式,並計算和輸出使用者輸入的任意表達式,例如:

> math1:factorial(6).
720
> math1:factorial(25).
15511210043330985984000000

以上的“>”代表 shell 提示符,該行的其他部分是使用者輸入的表示式。之後的行是表示式的求值結果。

factorial 的程式碼如何被編譯並載入至 Erlang 系統中是一個實現相關的問題。 [1]

在我們的例子中,factorial函式定義了兩個子句:第一個子句描述了計算factorial(0)的規則,第二個是計算factorial(N)的規則。當使用某個引數對factorial進行求值時,兩個子句按照它們在模組中出現的次序被依次掃描,直到其中一個與呼叫相匹配。當發現一個匹配子句時,符號->右邊的表示式將被求值,求值之前函式定義式中的變數將被代入右側的表示式。

所有的 Erlang 函式都從屬於某一特定模組。最簡單的模組包含一個模組宣告、匯出宣告,以及該模組匯出的各個函式的實現程式碼。匯出的函式可以從模組外部被呼叫。其他函式只能在模組內部使用。

程式1.2是該規則的一個示例。

程式1.2

-module(math2).
-export([double/1]).
double(X) ->
    times(X, 2).
times(X, N) ->
    X * N.

函式double/1可在模組外被求值[2],times/2則只能在模組內部使用,如:

> math2:double(10).
20
> math2:times(5, 2).
** undefined function: math2:times(5,2) **

在程式1.2中模組宣告-module(math2)定義了該模組的名稱,匯出屬性-export([double/1])表示本模組向外部匯出具備一個引數的函式double。

函式呼叫可以巢狀:

> math2:double(math2:double(2)).
8

Erlang 中的選擇是通過模式匹配完成的。程式 1.3 給出一個示例:

程式1.3

-module(math3).
-export([area/1]).
area({square, Side}) ->
    Side * Side;
area({rectangle, X, Y}) ->
    X * Y;
area({circle, Radius}) ->
    3.14159 * Radius * Radius;
area({triangle, A, B, C}) ->
    S = (A + B + C)/2,
    math:sqrt(S*(S-A)*(S-B)*(S-C)).

如我們所期望的,對math3:area({triangle, 3, 4, 5})得到6.0000而math3:area({square, 5})得到 25 。程式1.3 引入了幾個新概念:

    元組——用於替代複雜資料結構。我們可以用以下 shell 會話進行演示:

> Thing = {triangle, 6, 7, 8}.
{triangle, 6, 7, 8}
> math3:area(Thing).
20.3332

    此處Thing被繫結到{triangle, 6, 7, 8}——我們將Thing稱為尺寸為4的一個元組——它包含 4 個元素。第一個元素是原子式triangle,其餘三個元素分別是整數6、7和8。

    模式識別——用於在一個函式中進行子句選擇。area/1被定義為包含4個子句。以math3:area({circle, 10})為例, 系統會嘗試在area/1定義的子句中找出一個與{circle, 10}相符的匹配,之後將函式定義頭部中出現的自由變數Radius繫結到呼叫中提供的值(在這個例子中是10)。

    序列和臨時變數——這二者是在area/1定義的最後一個子句中出現的。最後一個子句的主體是由兩條以逗號分隔的語句組成的序列;序列中的語句將依次求值。函式子句的值被定義為語句序列中的最後一個語句的值。在序列中的第一個語句中,我們引入了一個臨時變數S。