使用Erlang實現乙個迭代器iterator

2021-08-23 13:35:53 字數 3827 閱讀 5948

最近比較忙, 一來是在努力學習erlang, 二來是戀戀不捨那幾個開源的小專案,三來是熟悉親愛的r13a...

加上令人頭疼的公司的事情, 導致我很忙... 哎...

為了保持部落格的新鮮度, 就貼一點充數的資料吧..呵呵...

在我前段時間搞的乙個開源的mapreduce小框架中, 對於map, reduce資料流的讀取, 我抽象出乙個迭代器, 進行資料的讀取.

這樣我的資料無論來自local disk, 來自memory, 來時nfs都一視同仁...

在寫乙個module之前,我先想象其介面及用法:

%%% usage:

%%% iter = make_iter(prev_fun, next_fun, state),

%%% = next(iter),

%%% = next(iter2),

%%% = prev(iter3).

我們首先通過呼叫make_iter/3 構建乙個迭代器, 第乙個引數是乙個函式用來獲取前一條記錄, 第二個引數用來獲取下一條

記錄. state是乙個內部狀態資訊, 用來儲存當前的狀態.

構造好iter後, 我們可以通過呼叫prev/1, next/1 來遍歷這個iter.

這個實現,有點oo的感覺在裡面, iter可以理解為乙個物件,其state為內部資料, prev_fun, next_fun為對應的方法.

為了讓我們的iter模組更豐富,我們仿照lists module, 加入了foldl/3 和 foldr/3 兩個函式.

當然還可以讓這個iter功能更強大,比如是否可以迴圈迭代?是否可以雙向或單向迭代?等等.有興趣朋友可以實現哦.

好了,貼上**:

-module(heng_iter).

-author('[email protected]').

-vsn('0.1').

-include("heng_master.hrl").

-export([make_iter/3]).

-export([next/1, prev/1]).

-export([foldl/3, foldr/3]).

-record(iter,

).%% @doc get the next item

next(#iter) ->

;next(iter = #iter) ->

case next(state) of

nil -> % to the end

; ->

, iter#iter}

end.

%% @doc get the item in the backward

prev(#iter) ->

;prev(iter = #iter) ->

case prev(state) of

nil -> % to the end

; ->

, iter#iter}

end.

%-spec foldl(fun :: fun(), acc :: term(), iter :: iter()) ->

% term().

foldl(fun, acc, iter) when is_function(fun, 2) ->

= next(iter),

foldl0(fun, acc, v, iter2).

foldl0(_fun, acc, nil, _iter) ->

acc;

foldl0(fun, acc, , iter) ->

acc2 = fun(v, acc),

= next(iter),

foldl0(fun, acc2, v2, iter2).

foldr(fun, acc, iter) when is_function(fun, 2) ->

= prev(iter),

foldr0(fun, acc, v, iter2).

foldr0(_fun, acc, nil, _iter) ->

acc;

foldr0(fun, acc, , iter) ->

acc2 = fun(v, acc),

= prev(iter),

foldr0(fun, acc2, v2, iter2).

%% @doc 'fward' equal 'forward' , 'bid' equal 'bidirectional'

make_iter(next, prev, state)

when is_function(next) andalso is_function(prev)

%andalso ((type =:= 'normal') or (type =:= 'cyclic'))

->

#iter.

最後是乙個小例子, 我們定義乙個迭代器,用來訪問list, 當然這個做法似乎有點多此一舉..

(這段**摘自 iter 模組中的測試** )

%% @doc some test

basic_test_() ->

data = ["begin", "one", "two", "there", "four", "end"],

expr1 = "begin one two there four end",

expr2 = "end four three two one begin",

%% 定義乙個迭代器, 其呼叫listnext/1 獲取下一條記錄, 呼叫listprev/1 獲取上一條記錄, state為乙個tuple

%% 分別儲存:資料的begin, last, length 和具體的資料(也就是list)

iter = make_iter(fun listnext/1, fun listprev/1, ),

r =

?module:foldl(fun(str, acc) ->

[str, $ | acc]

end,

,iter),

str = lists:flatten(lists:reverse(r)), % str 為 expr1

iter2 = make_iter(fun listnext/1, fun listprev/1, ),

r2 =

?module:foldr(fun(e, acc) ->

[e, $ | acc]

end,

,iter2),

str2 = lists:flatten(lists:reverse(r2)), % str 為 expr2

[?_assert(str = expr1),

?_assert(str2 = expr2)

].

%% 用來獲取下一條記錄

listnext() ->

nil;

listnext() ->

pos2 = pos + 1,

v = lists:nth(pos2, data),

}. %% 用來獲取前一條記錄

listprev() ->

nil;

listprev() ->

nil;

listprev() ->

pos2 = pos - 1,

v = lists:nth(pos2, data),

}.

好了就是這些, 有了這個module, 在mapreduce框架中,使用者可以自定義各種的iter 實現, map, reduce會依據使用者的iter

進行具體的資料讀取,然後進行處理..

詳細的**, 請參考此處:

[url]

學習STL,實現乙個單鏈表的迭代器

stl原始碼剖析中,空間配置器和迭代器屬於比較晦澀難懂的兩章,這裡學習了stl迭代器後也嘗試自己寫乙個迭代器,實現單鏈表的迭代器,實現不難,可以說是乙個玩具而已,但是能夠幫助我們理解stl迭代器的基本原理。宣告 templateclass listiterator templateclass lin...

Erlang 建立乙個簡單的TCP伺服器

一 建立 tcpserver.erl module tcpserver export start 0 start 建立乙個埠2345用於監聽來自客戶端的請求,是資訊表頭用4位元組表示長度,需要與客戶端一致 gen tcp listen 2345,binary,開始接受乙個請求 gen tcp acc...

Erlang之乙個簡單的TCP伺服器

簡單tcp伺服器 module my socket server export start 0,loop 1 start gen tcp listen 2345,binary,自定義打包規則,生成乙個監聽2345埠的socket gen tcp accept listen 生存乙個新的socket ...