莊周夢(mèng)蝶

          生活、程序、未來(lái)
             :: 首頁(yè) ::  ::  :: 聚合  :: 管理

          Erlang入門(一)

          Posted on 2007-06-13 14:36 dennis 閱讀(29182) 評(píng)論(4)  編輯  收藏 所屬分類: erlang
              讀erlang.org上面的Erlang Course四天教程
          1.數(shù)字類型,需要注意兩點(diǎn)
          1)B#Val表示以B進(jìn)制存儲(chǔ)的數(shù)字Val,比如
          7> 2#101.
          5
          進(jìn)制存儲(chǔ)的101就是10進(jìn)制的5了
          2)$Char表示字符Char的ascii編碼,比如$A表示65

          2.比較難以翻譯的概念——atom,可以理解成常量,它可以包含任何字符,以小寫字母開頭,如果不是以小寫字母開頭或者是字母之外的符號(hào),需要用單引號(hào)包括起來(lái),比如abc,'AB'

          3.另一個(gè)概念——Tuple,有人翻譯成元組,可以理解成定長(zhǎng)數(shù)組,是Erlang的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)之一:
          8> {1,2,3,4,5}.
          {
          1,2,3,4,5}
          9> {a,b,c,1,2}.
          {a
          ,b,c,1,2}
          10> size({1,2,3,a,b,c}).
          6
          內(nèi)置函數(shù)size求長(zhǎng)度,元組可以嵌套元組或者其他結(jié)構(gòu)。下面所講的列表也一樣。

          4.另外一個(gè)基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)就是各個(gè)語(yǔ)言都有的list(列表),在[]內(nèi)以,隔開,可以動(dòng)態(tài)改變大小,
              [123, xyz]
              [
          123, def, abc]
              [{person
          , 'Joe', 'Armstrong'},
                  {person
          , 'Robert', 'Virding'},
                  {person
          , 'Mike', 'Williams'}
              ]
          可以使用內(nèi)置函數(shù)length求列表大小。以""包含的ascii字母代表一個(gè)列表,里面的元素就是這些字母的ascii值,比如"abc"表示列表[97,98,99]。

          5.通過(guò)這兩個(gè)數(shù)據(jù)結(jié)構(gòu)可以組合成各種復(fù)雜結(jié)構(gòu),與Lisp的cons、list演化出各種結(jié)構(gòu)一樣的奇妙,Erlang也可以當(dāng)作是操作列表的語(yǔ)言。

          6.Erlang中變量有兩個(gè)特點(diǎn):
          1)變量必須以大寫字母或者下劃線開頭,可以包含字母、下劃線和@
          2)變量只能綁定一次,也就是所謂的Single Assignment。或者以一般的說(shuō)法就是只能賦值一次,其實(shí)Erlang并沒有賦值這樣的概念,=號(hào)也是用于驗(yàn)證匹配。

          7.模式匹配——Pattern Matching,Erlang的模式匹配非常強(qiáng)大,看了buaawhl的《Erlang語(yǔ)法提要》的介紹,模式匹配的功能不僅僅在課程中介紹的數(shù)據(jù)結(jié)構(gòu)的拆解,在程序的分派也扮演重要角色,或者說(shuō)Erlang的控制的流轉(zhuǎn)是通過(guò)模式匹配來(lái)實(shí)現(xiàn)的。具體功能參見鏈接,給出書中拆解列表的例子:
              [A,B|C] = [1,2,3,4,5,6,7]
                  Succeeds 
          - binds A = 1, B = 2,
                  C 
          = [3,4,5,6,7]
              
              [H
          |T] = [1,2,3,4]
                  Succeeds 
          - binds H = 1, T = [2,3,4]
              
              [H
          |T] = [abc]
                  Succeeds 
          - binds H = abc, T = []
              
              [H
          |T] = []
                  Fails

          下面會(huì)給出更多模式匹配的例子,給出一個(gè)模塊用來(lái)計(jì)算列表等

          8.Erlang中函數(shù)的定義必須在一個(gè)模塊內(nèi)(Module),并且模塊和函數(shù)的名稱都必須是atom,函數(shù)的參數(shù)可以是任何的Erlang類型或者數(shù)據(jù)結(jié)構(gòu),函數(shù)要被調(diào)用需要從模塊中導(dǎo)出,函數(shù)調(diào)用的形式類似:
          moduleName:funcName(Arg1,Arg2,...).
          寫我們的第一個(gè)Erlang程序,人見人愛的Hello World:
          -module(helloWorld).
          -export([run/1]).
          run(Name)
          ->
              io
          :format("Hello World ~w~n",[Name]).
          存為helloWorld.erl,在Erlang Shell中執(zhí)行:
          2> c(helloWorld).
          {ok
          ,helloWorld}
          3> helloWorld:run(dennis).
          Hello World dennis
          ok
          打印出來(lái)了,現(xiàn)在解釋下程序構(gòu)造,
          -module(helloWorld).
          這一行聲明了模塊helloWorld,函數(shù)必須定義在模塊內(nèi),并且模塊名稱必須與源文件名相同。
          -export([run/1]).
          而這一行聲明導(dǎo)出的函數(shù),run/1指的是有一個(gè)參數(shù)的run函數(shù),因?yàn)镋rlang允許定義同名的有不同參數(shù)的多個(gè)函數(shù),通過(guò)指定/1來(lái)說(shuō)明要導(dǎo)出的是哪個(gè)函數(shù)。
          接下來(lái)就是函數(shù)定義了:
          run(Name)->
              io
          :format("Hello World ~w~n",[Name]).
          大寫開頭的是變量Name,調(diào)用io模塊的format方法輸出,~w可以理解成占位符,將被實(shí)際Name取代,~n就是換行了。注意,函數(shù)定義完了要以句號(hào).結(jié)束。然后執(zhí)行c(helloWorld).編譯源代碼,執(zhí)行:
          helloWorld:run(dennis);

          9.內(nèi)置的常用函數(shù):
              date()
              
          time()
              
          length([1,2,3,4,5])
              size({a
          ,b,c})
              atom_to_list(an_atom)
              list_to_tuple([
          1,2,3,4])
              integer_to_list(
          2234)
              tuple_to_list({})
              hd([1,2,3,4])  %輸出1,也就是列表的head,類似Lisp的car
              tl([1,2,3,4])  %輸出[2,3,4],也就是列表的tail,類似List的cdr

          10.常見Shell命令:
          1)h(). 用來(lái)打印最近的20條歷史命令
          2)b(). 查看所有綁定的變量
          3) f(). 取消(遺忘)所有綁定的變量。
          4) f(Val).  取消指定的綁定變量
          5) e(n).   執(zhí)行第n條歷史命令
          6) e(-1).  執(zhí)行上一條shell命令

          11.又一個(gè)不知道怎么翻譯的概念——Guard。翻譯成約束?呵呵。用于限制變量的類型和范圍,比如:
               number(X)    - X 是數(shù)字
              integer(X)    
          - X 是整數(shù)
              float(X)    
          - X 是浮點(diǎn)數(shù)
              atom(X)        
          - X 是一個(gè)atom
              tuple(X)    
          - X 是一個(gè)元組
              list(X)        
          - X 是一個(gè)列表
              
              
          length(X) == 3    - X 是一個(gè)長(zhǎng)度為3的列表
              size(X) 
          == 2    - X 是一個(gè)長(zhǎng)度為2的元組
              
              X 
          > Y + Z    - X >Y+Z
              X 
          == Y        - X 與Y相等
              X 
          =:= Y        - X 全等于Y
              (比如: 
          1 == 1.0 成功
                         
          1 =:= 1.0 失敗)
          為了方便比較,Erlang規(guī)定如下的比較順序:
          number < atom < reference < port < pid < tuple < list
          其中pid就是process的id。

          12.忘了介紹apply函數(shù),這個(gè)函數(shù)對(duì)于熟悉javascript的人來(lái)說(shuō)很親切,javascript實(shí)現(xiàn)mixin就得靠它,它的調(diào)用方式如下:
          apply(Mod, Func, Args),三個(gè)參數(shù)分別是模塊、函數(shù)以及參數(shù)列表,比如調(diào)用我們的第一個(gè)Erlang程序:
          apply(helloWorld,run,[dennis]).
          13.if和case語(yǔ)句,if語(yǔ)句的結(jié)構(gòu)如下:
          if
          Guard1 ->
          Sequence1 ;
          Guard2 ->
          Sequence2 ;
          ...
          end
          而case語(yǔ)句的結(jié)構(gòu)如下:
          case Expr of
          Pattern1 [when Guard1] 
          -> Seq1;
          Pattern2 [when Guard2] 
          -> Seq2;

          PatternN [when GuardN] 
          -> SeqN
          end


          if和case語(yǔ)句都有一個(gè)問題,就是當(dāng)沒有模式匹配或者Grard都是false的時(shí)候會(huì)導(dǎo)致error,這個(gè)問題case可以增加一個(gè)類似java中default的:
          case Fn of

             _ 
          ->
             true
          end
          通過(guò)_指代任意的Expr,返回true,而if可以這樣:
          if
            

            true 
          ->
             true
          end
          一樣的道理。case語(yǔ)句另一個(gè)需要注意的問題就是變量范圍,每個(gè)case分支中定義的變量都將默認(rèn)導(dǎo)出case語(yǔ)句,也就是在case語(yǔ)句結(jié)束后可以被引用,因此一個(gè)規(guī)則就是每個(gè)case分支定義的變量應(yīng)該一致,不然算是非法的,編譯器會(huì)給出警告,比如:
          f(X) ->
          case g(X) of
          true 
          -> A = h(X), B = A + 7;
          false 
          -> B = 6
          end
          ,
          h(A)
          .

          如果執(zhí)行true分支,變量A和變量B都被定義,而如果執(zhí)行的false分支,只有變量B被定義,可在case語(yǔ)句執(zhí)行后,h(A)調(diào)用了變量A,這是不安全的,因?yàn)樽兞緼完全可能沒有被定義,編譯器將給出警告
          variable 'A' unsafe in 'case' (line 10)



          14.給出一些稍微復(fù)雜的模型匹配例子,比如用于計(jì)算數(shù)字列表的和、平均值、長(zhǎng)度、查找某元素是否在列表中,我們把這個(gè)模塊定義為list:
          -module(list).
          -export([average/1,sum/1,len/1,double/1,member/2]).
          average(X)
          ->sum(X)/len(X).
          sum([H
          |T]) when number(H)->H+sum(T);
          sum([])
          ->0.
          len([_
          |T])->1+len(T);
          len([])
          ->0.
          double([H
          |T]) -> [2*H|double(T)];
          double([]) 
          -> [].
          member(H
          , [H|_]) -> true;
          member(H
          , [_|T]) -> member(H, T);
          member(_
          , []) -> false.
                          

          細(xì)細(xì)體會(huì),利用遞歸來(lái)實(shí)現(xiàn),比較有趣,這其實(shí)與Lisp中利用尾遞歸來(lái)實(shí)現(xiàn)迭代是一樣的道理,[H|T]的形式類似Lisp中的car、cdr操作。_用于指代任意的變量,當(dāng)我們只關(guān)注此處有變量,但并不關(guān)心變量的值的時(shí)候使用。用分號(hào);來(lái)說(shuō)明是同一個(gè)函數(shù)定義,只是不同的定義分支,通過(guò)模式匹配來(lái)決定調(diào)用哪個(gè)函數(shù)定義分支。
          另一個(gè)例子,計(jì)算各種圖形的面積,也是課程中給出的例子:

          -module(mathStuff).
          -export([factorial/1,area/1]).
          factorial(
          0)->1;
          factorial(N) when N
          >0->N*factorial(N-1).
          %計(jì)算正方形面積,參數(shù)元組的第一個(gè)匹配square    
          area({square
          , Side}) ->
              Side 
          * Side;
          %計(jì)算圓的面積,匹配circle  
          area({circle
          , Radius}) ->
             
          % almost :-)
             
          3 * Radius * Radius;
          %計(jì)算三角形的面積,利用海倫公式,匹配triangle 
          area({triangle
          , A, B, C}) ->
             S 
          = (A + B + C)/2,
          math
          :sqrt(S*(S-A)*(S-B)*(S-C));
          %其他
          area(Other) 
          ->
             {invalid_object
          , Other}.

          執(zhí)行一下看看:
          1> c(mathStuff).
          {ok
          ,mathStuff}
          2> mathStuff:area({square,2}).
          4
          3> mathStuff:area({circle,2}).
          12
          4> mathStuff:area({triangle,2,3,4}).
          2.90474
          5> mathStuff:area({other,2,3,4}).
          {invalid_object
          ,{other,2,3,4}}

          Erlang使用%開始單行注釋。

          評(píng)論

          # re: Erlang入門(一)[未登錄]  回復(fù)  更多評(píng)論   

          2007-09-03 16:39 by -274°C
          希望交換鏈接,我最近也在學(xué)習(xí)Erlang。這方面交流的人還不多。

          # re: Erlang入門(一)  回復(fù)  更多評(píng)論   

          2007-09-03 16:51 by dennis
          好,有機(jī)會(huì)交流下學(xué)習(xí)Erlang,我也在繼續(xù)深入,已經(jīng)添加您的鏈接

          # re: Erlang入門(一)  回復(fù)  更多評(píng)論   

          2008-12-08 19:59 by Jizhaohui
          本文絕對(duì)是入門必讀的.
          非常清晰淺顯,值得入門者一讀!

          # re: Erlang入門(一)  回復(fù)  更多評(píng)論   

          2009-01-06 17:17 by 新溪
          我現(xiàn)在也在學(xué)這個(gè),打算盡快學(xué)出個(gè)所以然來(lái),弄個(gè)網(wǎng)絡(luò)五子棋玩玩。
          主站蜘蛛池模板: 清徐县| 肇庆市| 星座| 阳西县| 商丘市| 元江| 济南市| 革吉县| 高碑店市| 延安市| 石河子市| 昌乐县| 茶陵县| 惠水县| 类乌齐县| 司法| 乌海市| 荃湾区| 时尚| 临潭县| 宣威市| 玉山县| 溧水县| 门头沟区| 澎湖县| 蓝田县| 枣阳市| 宣恩县| 青岛市| 班玛县| 嘉荫县| 崇文区| 蕲春县| 日喀则市| 祁门县| 苍梧县| 城市| 石楼县| 阜宁县| 南平市| 高州市|