2014年9月18日

erlang的loop

本篇介紹如何使用erlang來達到java, javascript的for的寫法

首先先寫幾行簡單的程式碼,接著再示範如何重覆的執行這些程式碼, 程式碼如下。

connect()->
    {ok,S} = gen_tcp:connect({127,0,0,1},2222,[{packet,2}]), (1)
    Result = gen_tcp:send(S,<<"hello">>), (2)
    Result.

(1)使用tcp連線到server的2222 port

(2)送hello字串到server

如果我們要將connect()執行100次的話該如何寫? 由於erlang沒有內建的for可以使用,所以我們只能用遞迴(recursive)的寫法,如下

run()->
    T = 100,          
    connect(T),       
    ok.

connect(T)->          
    if
        T>0->         
            {ok,S} = gen_tcp:connect({127,0,0,1},2222,[{packet,2}]), (1)
            gen_tcp:send(S,<<"hello">>),  (2)
            connect(T-1); 
        true->
            ok
    end.

先改寫connect function,在該function增加一個參數叫T(執行次數),如果T>0的話就執行(1)連線至tcp server (2)送hello字串至server,接著將T-1後繼續呼叫connect function,如果T=0的話就結束,不再遞迴呼叫

增加run function,在該function定義T來儲存要執行100次,接著就使用使參數來呼叫connect function。

上述寫法會有一個缺點,connection function的邏輯應該專注在執行連線、送資料部份,但現在裡面多加了與邏輯無關的程式流程控制在裡面,我們來看下列改良的寫法

run()->
    R = for(1, 100, fun connect/1),         (1)
    io:format("R=~p~n", [R]),
    ok.

connect(I)->
    {ok,S} = gen_tcp:connect({127,0,0,1},2222,[{packet,2}]),
    Result = gen_tcp:send(S,<<"hello">>),
    {I,Result}.

for(Max, Max, F) -> [F(Max)];               (2)
for(I, Max, F) -> [F(I)|for(I+1, Max, F)].  (3)

此寫法增加了for/3 function來控制程式要執行幾次,connect function僅專注在連線、送資料。

首先來看(2)(3) for function的部份,該function有3個參數,第1個參數是起始值,第2個參數是結束值,第3個參數是所要執行的function,也就是connection/1

接著我們來看(1) for(1, 100, fun connect/1),這有點像我們一般習慣的for寫法,也就是描述要執行connect/1 100次。

首先會先呼叫到for(I, Max, F),所以會先執行F(I)也就是connect(1),接著再把I+1後呼叫for(I+1, Max, F)也就是for(2, 100, F)。最終執行到for(100,100,F)。

整個執行過程會像下列...最終會回傳一個list存著每個connection function的回傳值 [connect(1), connection(2), connection(3).....connect(100)]

另外erlang有提供foreach的function,該function適用時機在List值已知,將再List裡的值一個一個傳給function去執行,範例如下

test_foreach()->
    lists:foreach(fun connect2/1, ["hello", "how", "are", "you"]).

connect2(Text)->
    {ok,S} = gen_tcp:connect({127,0,0,1},2222,[{packet,2}]),
    gen_tcp:send(S,term_to_binary(Text)).

上述的例子總共會執行4次connect2,代入的connection2參數依次為"hello", "how", "are", "you"

小結

在java裡用到遞迴的機會不多,或許可以用其它的寫法躲過遞迴,但踏入erlang後遞迴是閃不掉的,還是得花時間適應。