Erlang 基本語法

打算開始介紹 Erlang 語言,幾乎都先要從語法開始。但是,根據我寫維基百科 Erlang 條目的經驗,會把語法部份的表達帶往流水帳的格式,這樣很無聊。所以,我這篇先把語法中比較顯要的幾個項目提一下。

1. 語法包括哪些東西

當您站在講台上教電腦程式語言,談到 C ,您會想到先教 assignment ,然後 if-else 或 switch ,然後 for 或 while 或 do-while 迴圈,然後介紹陣列,然後可以隨意談一談函數或指標變數。

現在,請把腦中清空,忘掉變數指派賦值,忘掉迴圈,忘掉條件判斷 ── 接受「程式語言並不全都是這樣子」的觀念。 (保持幾秒中想像著白開水 …… 好,我們開始!)

Erlang 有哪些東西?它有變數,是在執行範圍中只能賦值一次的「變」數。它沒有迴圈,要做循環程序請使用遞迴語法。它有 case 敘述,意思跟 C 語言的 switch 一模一樣。它有 if 敘述,跟自己的 case 敘述很像。它有列表,但是沒有陣列,不過沒關係,列表用起來很像 linked list 。它當然有函數,全部的程式內容都是函數,而且函數可以傳入任何結構的資料,也可以傳回任何結構的資料。函數本身也可以當做參數。 Erlang 還有許多以模組方式組織的程式庫,可以借用一些好用的功能。

Erlang 沒有指標,因為沒有使用的場合:變數全都是只賦值一次,所以,不會有哪一個新算出的數值要指派到任何一個已經用過的變數裏頭。沒有 call-by-pointer 或 call-by-reference ,不過, Erlang 有 call-by-name

Erlang 自己的特色,擁有 ! 表示對某 process 送訊息,有 receive 敘述表示取回自己 process 收到的訊息。

2. = 符號

Erlang 也有變數,但是沒有 assignment 。既然有變數,它當然也有一種運算方式把某個東西跟一個變數連接在一起,有點像 assignment ,但不是 assignment 。這種動作稱為「樣式匹配」。假設 A B 是二個任意式子,當你看到

        A = B

意思就是把 B 匹配到 A 。這樣可能會匹配,或者也可能不匹配。匹配是指構成 A 式的格式與 B 式的構成相同。那麼,接下來要討論二種狀況下,運算的結果是什麼:

  1. 匹配成功:所有 A 式子中本來沒有賦值的變數都會被賦上 B 式中對應的值,然後整體傳回 B 式的值。
  2. 匹配失敗:傳回 false 。匹配失敗是一種例外情況,會使程式中斷,因此提醒程式人員趕緊來修好程式。

而且,任何一個變數在它的執行範圍只可以賦值一次。變數跟某個值連接在一起之後,就永遠代表那個值。

3. 遞迴

有些批評者很愛說:「因為 Erlang 都用遞迴,最大的問題就是 stack overflow 。」這句話基本上沒錯,不過,站在 C 語言的思考方式,才會以為無論如何這都是大災難。但我們這裏釐清這個觀點:

  • C 語言的遞迴:直接與系統環境的 stack 觀念連結。為了執行遞迴,它要先把呼叫端的程式狀態全部儲存到堆疊中,然後才執行被呼叫端。
  • Erlang 的遞迴:語法上告訴你是遞迴,但是系統環境中也使用到 register-based 方式來加強效率。

換句話說, C 語言整體是利用 register 讓程式運作,而 Erlang 是語法看起來是遞迴,不過底層也用到 register 的方式執行。所以,在擔心到 stack overflow 之前,請您先好好享受 Erlang 隨便就能算出一個超大數值的能力 ── 而 C 語言使用者通常都對大數運算傷透腦筋。在函數語言領域也有一些寫程式的方法,像是 tail recursion ,能減少遞迴運算的 stack 使用量。

4. case 敘述

case 敘述的語法是:

        case Something of
                 Firse_Case ->
                         ... ;
                 Another_Case ->
                         ... ;
                 ......
                         ...... ;
                 Others ->
                         ...
         end 

判斷一個變數可以匹配哪一種情況,然後就做那一種情況的動作。所以 First_Case , Another_Case 和 Others 這些情況都寫成資料值,或者有用到未賦值的變數。匹配之後,case 中的變數會賦值,在匹配之後可以使用。

5. if 敘述

if 敘述的語法是:

        if
                First_Condition ->
                        ... ;
                
                Another_Condition ->
                        ... ;
                ...
                        ... ;
                Final_Condition ->
                        ...
        end 

基本是要做一些判斷、比對,然後才執行對應到的動作。在 First_Condition , Another_Condition 和 Final_Condition 會用到判斷式,不會用到樣式匹配。

6. 列表

列表是表示一串資料的表達方式,只要用方括號與逗點分隔資料就可以表示一串資料:

        [a,b,c,d,e]

小寫的文字稱為原子,代表最基礎的資料類型。用 [] 表示沒有資料的列表。但是,列表可以有很多種樣子,樣式匹配會很麻煩,於是有一種列表的縮寫法,可以用在樣式批配。

        [Head|Tail] = [a,b,c,d,e]

首字母大寫的 Head 和 Tail 是變數。 Head 匹配到列表第一項, Tail 匹配到除第一項之外的子列表。像以上例子, Head 匹配結果得到 a , Tail 匹配結果得到 [b,c,d,e] 。

7. ! 符號

! 是傳送訊息的符號。假設有一個 process 代號被賦值到 Pid 變數中,則以下例子是對此 process 送一筆資料:

        Pid ! hello_world

8. receive 敘述

使用 receive 敘述可以從自己 process 的 mailbox 取到一筆 process 接收的訊息。語法為:

         receive
                Firse_Case ->
                        ... ;
                Another_Case ->
                        ... ;
                ......
                        ...... ;
                Others ->
                        ...
         end 

First_Case , Another_Case 和 Others 是一些要匹配的樣式,可能是資料值或是包含未賦值的變數。匹配之後,case 中的變數會賦值,在匹配之後可以使用。

9. 列表解析

集合論有個稱為 set builder 的東西:如果您要建立一個集合,可以用規則定義集合的元素來說明。例如: E = { x | x > 0, x / 2 in E } 定義正偶數。 Erlang 有很類似的東西稱為 list comprehension ,有些翻譯成列表解析。同樣的正偶數定義,在 Erlang 寫成

[ X || X <- [0,1,2,3,4,5,6,7,8,9,10], X >  0, X rem 2 == 0 ]

X <- [0,1,2,3,4,5,6,7,8,9,10] 在列表解析的意思是從 [0,1,2,3,4,5,6,7,8,9,10] 取出每一個元素,放到 X 。在這裏, X 是一個非常特別的變數。 rem 是除法取餘數的運算子。整個列表解析式子是只有 X > 0, X rem 2 == 0 的元素才會收集起來。所以,最後得到 [2,4,6,8,10] 。

語法介紹到此,其他豐富的細節,日後再談。

廣告

About 黃耀賢 (Yau-Hsien Huang)

熱愛 Erlang ,並且有相關工作經驗。喜歡程式語言。喜歡邏輯。目前用 Python 工作。
本篇發表於 Erlang, Introduction。將永久鏈結加入書籤。

4 Responses to Erlang 基本語法

  1. DonaldIsFreak 說道:

    對Erlang的if expression比較特別的地方,是最後都要加個true的Guard,不然都會丟出錯誤,另外。 pattern matching是整個Erlang核心概念之一,每次看別人的程式碼時,大腦就會開始發熱。(@_@)
    感謝對Erlang發文:D

    • 黃耀賢 (Yau-Hsien Huang) 說道:

      if expression 一定要有最後 true 規則嗎? 我以前印象是, 但是最近寫維基條目有一次測試, 做到最後沒有加 true -> … 也可以運行. 所以關於這一點加以保留, 不介紹執行上的細節, 以免一開始要記憶太多東西.

      • shian 說道:

        if 最後不一定要有 true。如果 if 中的子句沒有一個是 true 的話,則 if 會失敗,丟出個 exception,因此習慣中最後會加上個 true 來處理這種情形。

      • 黃耀賢 (Yau-Hsien Huang) 說道:

        對, 我前陣子寫Wikipedia條目和Wikibooks, 當時有測過一些程式, 印象是的確不需要補 true case.

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s