學習Erlang--1、入門


1、正式起航

從前,一名程序員偶然讀到了一本古怪的語言圖書,相等其實不是相等,變量其實是不能改變的,語法是那么陌生,它甚至不是面向對象,這些程序實在是太過另類……

另類的不僅僅是程序,編程的教學步驟也特立獨行,它的作者一直喋喋不休地教授並發、分布和容錯,不斷的嘮叨着一種叫COP(Concurrency Oriented Programming,面向並發編程)的方法,管它叫什么……

不過有些程序看起來很好玩,那天夜里,這個程序員注視着那個聊天程序的小例子,它是多么的小巧可愛而又通俗易懂,它確實簡單到不能再簡單了,用不了幾行代碼,文件共享和加密通信便躍然而上,於是這個程序員開始敲起了他的鍵盤……

上面這段話非常簡單有趣,而又把Erlang的特點很好的帶了出來,使我和那個提到的程序員一樣,開始了我的Erlang之旅。

2、Erlang安裝

在Erlang的官方網站http://www.erlang.org/ 可以找到它的安裝程序,

image

由於我的是windows系統,所以我直接進入Download頁面,找到Windows Binary File下載就行了。

image

等下載好之后的安裝也非常簡單,直接next就行,完成后就可以在開始菜單找到

image 這么一個東東,打開后就能看到

image

這個就是我們得Erlang的一個模擬器了,當然,使用windows的cmd或者unix下的bash在命令提示符下輸入erl來啟動Erlang shell--erl也是一樣的。

我們嘗試一下,如下圖輸入

image

提示符 1> 說明這是我們的第一個命令,% 號后面跟着的是注釋文字,它表示此行都是Erlang的注釋,會被shell和Erlang編譯器忽略。

第二行輸入20+30,然后回車,沒有出結果?因為在Erlang中是以 “. + 回車”來表示一個完整命令的結束的,

所以第三行還是提示的1>,表示我們的第一個命令還是沒結束,然后我們輸入 “.”和回車,這時候shell會對表達式求值,並打印出結果,50.

然后顯示的提示符就編程2>,表示我們下面開始的就是第2個Erlang命令了。

另外,之前錄入的命令我們可以通過shell的Ctrl+N,Ctrl+P快捷鍵來找回。

如果程序命令輸入有誤,已經到了不可挽回的地步,系統沒有任何響應,那么按Ctrl + break(windows系統)你會看到下面的提示:

image

這個時候按A就能中止當前Erlang會話

3、入門

3.1、簡單的整數運算

先計算幾個算數表達式

image

Erlang遵守標准算術表達式法則,因此20+30*40實際上是20+(30*40)而不是(20+30)*40

Erlang采用不定長的整數來進行整數的算術演算,因此不用擔心溢出,例如:

image

還可以用不同的方式來輸入整數,例如:

image

3.2、變量

怎樣才能將一個命令的結果保存下來以供后面使用呢?這就是變量了,例如:

image

上面例子表示我們向一個變量X賦了一個值,然后打印出變量的值

如果我們要查看變量的值,可以輸入

image

有了X變量,我們還可以這么使用

image

代數式的單一賦值

在初中,數學老師告訴我們,在同一個方程的不同地方都有X,那么這些X指的都是同一個東西;

但是當我們開始學習第一門程序語言時,看到X=X+1,我們都懵了,這個等式明顯不成立!但是老師卻說我們錯了,X不是一個數學變量,而是一個盒子……

而在Erlang中,變量恢復了它在數學中的涵義,當你將一個變量和值關聯在一起時,你就相當於做出了一種斷言,就是對事實的一個陳述,僅此而已。

然而,如果你想要給X賦一個新的值,那么系統會無情的拋給你一個錯誤信息:

image

這個是怎么回事?嗯,要解釋它我們必須破除兩個錯誤的想法:

1)X並不是傳統意義上的變量,至少不是我們在C/C++/C#中用到的那種;

2)=不是一個賦值操作符。

3.2.1、變量不變

Erlang的變量是單一賦值變量,即變量的值只能一次性的給定。

一個變量如果含有一個被賦予的值,那么它就被稱為綁定變量,否則就是自由變量。

就本質而言,=是一個模式匹配符,當變量是一個自由變量時,它的行為與賦值一致。

最后,定義一個變量的詞法單元就是這個變量的作用域。因此在一個函數語句中使用的變量,那么這個變量的值就不能跳出語句之外。

在同一個函數的不同子句中,彼此也不存在全局或者共享的私有變量。如果X出現在許多不同函數中,那么這些X的值也都是各自獨立的。

3.2.2、模式匹配

在大多數語言中,=都表賦值語句;但是在Erlang中,=表示一個模式匹配操作。

Lhs=Rhs實際上是這樣一個過程,對右端求值(Rhs),然后將結果與左端(Lhs)進行模式匹配。

一個變量,比如X,就是一個最簡單的模式,當我們第一次輸入X=something時,Erlang會問自己,“要怎么做會讓這個語句的值變為true?”,由於X沒有被賦值,於是將something的結果綁定到X上,使語句有效,結果皆大歡喜。

但是,隨后輸入X=anotherthing的時候,由於X已經是綁定變量了,只有當something的值與anotherthing一致時這個語句才會成立,否則就會拋出異常。例如:

image

3.2.3、單一賦值為何有益於編寫質量更高的代碼

Erlang里面的變量僅僅是對值的一個引用,就具體實現而言,一個綁定變量就是一個指針,這個指針指向那個值的存儲區。那個值是無法改變的。

拋棄“副作用”意味着我們的程序可以並行化

用術語來說,我們把可以修改的內存區域稱為可變狀態。Erlang是一個函數式語言,不存在可變狀態。

當多核編程來臨的時候,我們會發現采用不可變狀態帶來的好處是難以估量的。

像C或者JAVA這樣的傳統語言在為多核CPU編程時,遇到內存共享的問題,要想不破壞內存共享就必須在訪問時加鎖,還要保證在操縱共享內存時程序不會崩潰。而Erlang沒有可變狀態,也沒有共享內存,更沒有鎖,這些都有利於並行化程序的編寫。

那么你又會問,沒有變量那怎么去描述X=X+1這種表達式呢?答案很簡單,采用一個新的變量,例如X1,使X1=X+1

(好吧。。。其實我看到這里的時候噴了一顯示器。。。)

3.3、浮點數

讓我們用浮點數做一些運算:

image

注意,第一行最后是整數“3”,那個點表示結束表達式,而不是小數點,如果要表示一個浮點數應該寫成“3.0”

“/”永遠返回浮點數,所以第2個表達式中的“4/2”結果不是2,而是2.0。

div和rem表示整數除和取余數。

3.4、原子

在Erlang中,原子用來表示不同的非數字常量值。

    類似於C中的:#define OP_READ 1 這種宏定義。

Erlang中的原子是全局有效的,而且無需使用宏定義或者包含文件。

原子是一串以小寫字母開頭,后跟數字、字母或者下划線(_)或者郵件符號(@)的字符,

    例如monday、abc_d、aaa@somehost等。

使用單引號引起來的字符也是原子,使用這種形式,我們就能使得原子可以用大寫字母作為開頭或者包含非數字字符,

    例如‘+’、‘a b c’等。

一個原子的值就是原子自身。

討論原子或者整數的值聽上去多少有些奇怪,但是因為Erlang是個函數式語言,每一個表達式都必須有值,整數和原子這些特別簡單的表達式也不例外。

3.5、元組

你若想將一定數量的項組成單一的實體,那么就可以使用元組(tuple)。

將若干個以逗號分隔的值,用一對花括號括起來,就形成了一個元組。

例如一個叫joe的人身高1米8,那么用元組就可以表示為 { joe, 180 }。

元組類似於C中的結構,C語言中要定義point類型的變量p,要這么做:

image

並通過點來訪問一個結構的字段,例如:

image

但是在Erlang中沒有類型聲明,因此創建一個point會是這個樣子:

image

這個語句創建了一個元組,並將其綁定給了變量P。

和C不同的是元組沒有字段名稱,為了方便記憶可以給元組添加一個原子作為其第一個元素,來標記這個元組的含義,

因此我們可以采用 { point, 10, 45 } 來代替上面的元組,這樣更清晰。

元組可以嵌套,例如下面的例子:

image

3.5.1、創建元組

在聲明元組時就自動創建了元組,不再使用它們時,元組也隨之銷毀,Erlang使用垃圾收集器去收回沒有使用的內存,因此我們不用擔心內存分配的問題。

如果你創建的元組引用了一個已經綁定的變量,那么新元組就會享有這個變量所引用的數據結構。例如:

image

而若在創建數據結構時試圖引用一個未定義的變量,那么系統就會給出一個錯誤。

3.5.2、從元組中提取字段值

此處就要用到我們之前提到的模式匹配符= 了。

回到之前元組表示點的例子:

image

若想提出點的坐標值怎么做呢?如下所示:

image

作為演示,我們使用一個復雜的元組:

image

下面我們要獲取他的姓,按如下寫法

image

最后打印出who

image

符號_稱為匿名變量,與常規變量不同,在同一個模式中的不同地方,各個 _ 所綁定的值不必相同。

3.6、列表

我們用列表存儲數目可變的東西,如在商場購買的商品、行星的名字、公交的站點等等。

將若干以逗號分隔的值,用一對方括號括起來,就形成了一個列表。

下面的例子就是一個購物清單的列表:

image

列表中的各個元素可以有不同的類型,例如

image

3.6.1、術語

列表的第一個元素稱為列表的頭(head),那么剩下的,就稱為列表的尾(tail)。

列表的頭可以是任何東西,但是列表的尾還是一個列表。

訪問列表的頭是一個非常高效的操作,因此,實際上所有的列表處理函數都是從提取列表的頭開始的,先對頭進行處理,然后再繼續處理列表的尾。

3.6.2、定義列表

如果T是一個列表,那么 [ H | T ] 也是一個列表,這個列表以H為頭,以T為尾。

豎線|符號可以將列表的頭和尾分隔開,而 [ ] 則是表示空列表。

無論何時,我們用 [ … | T ] 來構建一個列表時,都應保證T是一個列表,如果T是一個列表,那么新的列表就是“正規形式”,反之就是“非正規列表”。大多數函數庫都假定列表時正規的,它們不能正確處理非正規列表。

可以用 [ E1, E2, …, En | T ] 這種形式向T的起始處加入多個新元素,例如

image

3.6.3、從列表中提取元素

我們可以用模式匹配操作從一個列表中獲取元素,假定現在有一個非空列表L,那么表達式 【X | Y】=L (X,Y都是變量)可以把列表頭提取到X,可以把列表尾提取到Y。

如果我們有個超市購物的列表清單,首先要做的就是把列表分解成頭和尾:

image

那么這個Buy1的值就是 { oranges, 4 } ,ThingsToBuy2的值就是后面元素組成的列表。

3.7、字符串

嚴格來講,Erlang沒有字符串,字符串實際上就是一個整數列表。

用雙引號將一串字符括起來,就形成了一個字符串。例如:

image

注意,Erlang中只能使用雙引號表示字符串,而不能使用單引號。

這里的 ”Hello”僅僅是一個速記形式,實際上它意味着一個整數列表,列表中每一個元素都是相應字符的整數值。

shell打印一串列表值時,只有當列表中的所有整數都是可打印的字符,它才將這個列表當做字符串來打印,例如:

image

我們無需死記硬背哪個整數表示哪個字符,可以使用$符號來表示字符的整數,例如$a就是一個整數,表示字符a,再有:

image

字符串中使用的字符集

字符串中的字符是Latin-1(ISO-8859-1),例如一個含有瑞典名字的字符串image會被編碼成為image

如果在shell中將image作為表達式輸入,你可能看不到想要的結果,這實際上是顯示終端的字符集和區域設定的問題,Erlang對於這類問題束手無策。

3.8、再論模式匹配

逐行研究下表的例子,確保真正掌握了這些

image

可以在shell中輸入 模式=值 來查看運行結果

image

命令f()會讓shell釋放它所綁定過的所有變量,使用這個命令后,所有的變量都變成了自由變量

現在我們對基本的數據類型已經非常熟悉了,對單一賦值和模式匹配也有了了解,因此我們可以加快步伐進入下一章,學習如何定義函數和模塊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM