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。