`
litaocheng
  • 浏览: 337718 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用Erlang实现一个迭代器iterator

阅读更多
最近比较忙, 一来是在努力学习Erlang, 二来是恋恋不舍那几个开源的小项目,三来是熟悉亲爱的R13A...
加上令人头疼的公司的事情, 导致我很忙... 哎...

为了保持博客的新鲜度, 就贴一点充数的资料吧..呵呵...

在我前段时间搞的一个开源的mapreduce小框架中, 对于map, reduce数据流的读取, 我抽象出一个迭代器, 进行数据的读取.

这样我的数据无论来自local Disk, 来自memory, 来时NFS都一视同仁...

在写一个module之前,我先想象其接口及用法:
%%% usage:
%%%  Iter = make_iter(prev_fun, next_fun, State),
%%%  {Next , Iter2} = next(Iter),
%%%  {Next2, Iter3} = next(Iter2),
%%%  {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('litaocheng@gmail.com').
-vsn('0.1').
-include("heng_master.hrl").

-export([make_iter/3]).
-export([next/1, prev/1]).
-export([foldl/3, foldr/3]).

-record(iter,
        {  
            %type = normal :: 'normal' | 'cyclic', % 
            next = nil :: 'nil' | fun(),
            prev = nil :: 'nil' | fun(),
            state
        }).

%% @doc get the next item
next(#iter{next = nil}) ->
    {error, edirection};
next(Iter = #iter{next = Next, state = State}) ->
    case Next(State) of
        nil -> % to the end
            {nil, Iter};
        {V, State2} ->
            {{value, V}, Iter#iter{state = State2}}
    end.
    
%% @doc get the item in the backward
prev(#iter{prev = nil}) ->
    {error, edirection};
prev(Iter = #iter{prev = Prev, state = State}) ->
    case Prev(State) of
        nil -> % to the end
            {nil, Iter};
        {V, State2} ->
            {{value, V}, Iter#iter{state = State2}}
    end.

%-spec foldl(Fun :: fun(), Acc :: term(), Iter :: iter()) -> 
%    term().
foldl(Fun, Acc, Iter) when is_function(Fun, 2) ->
    {V, Iter2} = next(Iter),
    foldl0(Fun, Acc, V, Iter2).

foldl0(_Fun, Acc, nil, _Iter) ->
    Acc;
foldl0(Fun, Acc, {value, V}, Iter) ->
    Acc2 = Fun(V, Acc),
    {V2, Iter2} = next(Iter),
    foldl0(Fun, Acc2, V2, Iter2).
    
foldr(Fun, Acc, Iter) when is_function(Fun, 2) ->
    {V, Iter2} = prev(Iter),
    foldr0(Fun, Acc, V, Iter2).

foldr0(_Fun, Acc, nil, _Iter) ->
    Acc;
foldr0(Fun, Acc, {value, V}, Iter) ->
    Acc2 = Fun(V, Acc),
    {V2, Iter2} = 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{%type = Type,
          next = Next,
          prev = Prev,
          state = State
          }.



最后是一个小例子, 我们定义一个迭代器,用来访问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, {0, 0, length(Data), Data}),
    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, {length(Data)+1, 1, length(Data), Data}),
    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({Last, _First, Last, _Data}) ->
    nil;
listnext({Pos, First, Last, Data}) ->
    Pos2 = Pos + 1,
    V = lists:nth(Pos2, Data),
    {V, {Pos2, First, Last, Data}}. 
    
%% 用来获取前一条记录
listprev({0, _First, _Last, _Data}) ->
    nil;
listprev({First, First, _Last, _Data}) ->
    nil;
listprev({Pos, First, Last, Data}) ->
    Pos2 = Pos - 1,
    V = lists:nth(Pos2, Data),
    {V, {Pos2, First, Last, Data}}.  


好了就是这些, 有了这个module, 在mapreduce框架中,用户可以自定义各种的iter 实现, map, reduce会依据用户的iter
进行具体的数据读取,然后进行处理..

详细的代码, 请参考此处:
http://code.google.com/p/heng/source/browse/trunk/master/heng_iter.erl
分享到:
评论

相关推荐

    一种傻纸牌游戏的Erlang实现

    标题 "一种傻纸牌游戏的Erlang实现" 暗示了我们将探讨一个使用Erlang编程语言构建的简单纸牌游戏。Erlang是一种并发性极强、功能丰富的函数式编程语言,常用于构建分布式系统和高可用性的应用程序。 在描述中提到的...

    Erlang-game-server开发实践.pdf

    在本文中,我们将介绍如何使用Erlang开发一个简单的游戏服务器,并讨论其优点和实现细节。 Why Erlang? Erlang是一种轻量级的语言,非常适合开发高性能的服务器应用程序。其主要优点有: * 轻量级process:...

    erlog, 在Erlang中,Prolog解释器.zip

    erlog, 在Erlang中,Prolog解释器 Erlog - 用于Erlang应用程序的PrologErlog是在Erlang中实现的Prolog解释器,并与Erlang运行时系统集成。 它是Prolog标准的子集。 还包括 Erlog shell ( REPL ) 。如

    二郎助手erlang开发工具、erlang编辑器

    作为一个基于VS2005开发的项目,它继承了Visual Studio家族的强大编辑器功能,并且针对Erlang语言进行了优化。这意味着开发者可以在一个熟悉的环境中进行Erlang编程,而无需适应新的开发环境。 在二郎助手中,你...

    Python-一个用Python实现的Erlang结点使用gevent库

    标题中的“Python-一个用Python实现的Erlang结点使用gevent库”指的是一个Python项目,该项目旨在实现Erlang的节点功能,但完全使用Python语言编写,并且利用了gevent库来提高并发性能。Erlang是一种用于构建高可用...

    使用erlang连接ES的客户端

    目前,有多个Erlang库可以实现这一功能,如`es_client`可能就是这样的一个库。这个库提供了与Elasticsearch通信的API,使得开发者能够方便地发送HTTP请求到ES集群进行索引、查询、更新等操作。 **安装Erlang ES...

    使用erlang的动态执行编写DSL

    2. `dsc.txt` - 这可能是一个描述文件,用于解释DSL的结构或者提供DSL的使用指南。它可能包含了DSL的语法规则、示例和如何在Erlang程序中调用和解析DSL的说明。 3. `biz_rules.txt` - 业务规则文件,很可能包含了...

    使用Erlang和Yaws开发REST式的服务

    总的来说,Erlang和Yaws的组合为构建RESTful服务提供了一个强大而灵活的平台,尤其适合需要高并发和稳定性的场景。虽然静态文件服务器如lighttpd或nginx可能在处理静态内容方面更高效,但Erlang和Yaws在动态内容和...

    erlang的timer和实现机制

    每个定时器实际上都是一个单独的进程,当设置定时器时,Erlang调度器会在后台创建一个进程来跟踪时间。这个进程会在预定的时间点唤醒,执行相应的操作,如发送消息或调用函数。这种基于进程的实现方式保证了定时器的...

    erlang ranch实现的游戏tcp服务器

    标题"erlang ranch实现的游戏tcp服务器"表明我们将探讨如何利用Ranch库来创建一个针对游戏场景的TCP服务器。在这个项目中,我们可能涉及到以下几个核心知识点: 1. **Erlang语言基础**:Erlang是一种函数式编程语言...

    erlang聊天室源码

    本篇将深入探讨一个基于Erlang实现的简单聊天室源码,帮助初学者理解Erlang在构建实时通信系统中的应用。 首先,`聊天室需求文件.doc`提供了项目的基本需求,通常会包含聊天室的功能描述、用户交互方式、性能指标等...

    Redis 的 Erlang 实现.zip

    如果您在使用此库时发现任何错误或遇到问题,请在此 repo 中打开一个问题(或拉取请求:))。您可以在inaka.github.io查看我们所有的开源项目用法只需运行$ make run并打开您最喜欢的 redis 客户端的连接。与 Redis ...

    用Erlang写了个解八数码的小程序

    标题中的“用Erlang写了个解八数码的小程序”指的是使用Erlang编程语言实现的一个解决8数码问题(也称为滑动拼图)的算法。8数码问题是一个经典的计算机科学问题,它涉及到在一个3x3的网格上,通过空格与其他数字...

    erlang资源

    Erlang是一种面向并发的、函数式编程语言,由瑞典...这两本书结合阅读,将为初学者提供一个全面的Erlang学习路径,从基础语法到高级并发编程技巧,有助于深入理解Erlang语言及其在构建高并发、分布式系统中的强大能力。

    一个我自己学习Erlang的聊天室服务器及客户端代码

    本项目提供了一个使用Erlang编写的聊天室服务器端代码以及Java编写的客户端代码,这为我们深入理解Erlang的并发特性和Java与Erlang的交互提供了实践案例。 一、Erlang聊天室服务器端 1. 并发处理:Erlang的轻量级...

    erlang编程 Introducing Erlang

    当一个节点或进程失败时,系统可以重新分配工作,确保服务的连续性。 ### 9. BEAM虚拟机 BEAM是Erlang运行时系统的名称,全称为伯尔尼高级执行机器(Bergen Erlang Virtual Machine)。它负责解释Erlang字节码,...

    erlang写的一个特别的web服务器

    总的来说,emongrel2是Erlang对Mongrel2的实现,它结合了Erlang的并发优势和Mongrel2的设计理念,旨在构建一个高性能、可扩展、安全的Web服务器。对于熟悉Erlang和想要在高并发场景下部署Web服务的开发者来说,这是...

    在erlang项目中使用protobuf例子

    6. **Erlang与protobuf的交互**:Erlang的并发和分布式特性使得protobuf成为实现高可用和高性能系统的一个理想选择。你可以使用protobuf在Erlang节点间交换消息,或者与其他支持protobuf的语言(如Java、Python等)...

    lambdapad, 使用Erlang的static 站点生成器 是的,Erlang.zip

    lambdapad, 使用Erlang的static 站点生成器 是的,Erlang LambdaPad Erlang power站点生成,仓库 !查看Lambda在 lambdapad.io 生成文档。 这是递归 !

Global site tag (gtag.js) - Google Analytics