2013-02-09 43 views
1

我基本上遵循本网站上的教程Learn you some Erlang:Designing a concurrent application,我试图用下列命令运行下面的代码,并在第48行出现错误。我确实关闭了防火墙,以防万一问题,但没有运气。我在Windows XP SP3上。Erlang进程事件错误

9> c(事件)。

{ok,event}

10> f()。

ok

11> event:start(“Event”,0)。

=错误报告==== 9-FEB-2013 :: 15:05:07 === 错误在过程< 0.61.0>与出口值:{function_clause,[{事件,time_to_go,[0 ],[{file,“event.erl”},{line,48}]},{event,init,3,[{file,“event.erl”},{line,31}]}]}

< 0.61.0>

12>

-module(event). 
-export([start/2, start_link/2, cancel/1]). 
-export([init/3, loop/1]). 
-record(state, {server, 
       name="", 
       to_go=0}). 

%%% Public interface 
start(EventName, DateTime) -> 
    spawn(?MODULE, init, [self(), EventName, DateTime]). 

start_link(EventName, DateTime) -> 
    spawn_link(?MODULE, init, [self(), EventName, DateTime]). 

cancel(Pid) -> 
    %% Monitor in case the process is already dead 
    Ref = erlang:monitor(process, Pid), 
    Pid ! {self(), Ref, cancel}, 
    receive 
     {Ref, ok} -> 
      erlang:demonitor(Ref, [flush]), 
      ok; 
     {'DOWN', Ref, process, Pid, _Reason} -> 
      ok 
    end. 

%%% Event's innards 
init(Server, EventName, DateTime) -> 
    loop(#state{server=Server, 
       name=EventName, 
       to_go=time_to_go(DateTime)}). 

%% Loop uses a list for times in order to go around the ~49 days limit 
%% on timeouts. 
loop(S = #state{server=Server, to_go=[T|Next]}) -> 
    receive 
     {Server, Ref, cancel} -> 
      Server ! {Ref, ok} 
    after T*1000 -> 
     if Next =:= [] -> 
      Server ! {done, S#state.name}; 
      Next =/= [] -> 
      loop(S#state{to_go=Next}) 
     end 
    end. 

%%% private functions 
time_to_go(TimeOut={{_,_,_}, {_,_,_}}) -> 
    Now = calendar:local_time(), 
    ToGo = calendar:datetime_to_gregorian_seconds(TimeOut) - 
      calendar:datetime_to_gregorian_seconds(Now), 
    Secs = if ToGo > 0 -> ToGo; 
       ToGo =< 0 -> 0 
      end, 
    normalize(Secs). 

%% Because Erlang is limited to about 49 days (49*24*60*60*1000) in 
%% milliseconds, the following function is used 
normalize(N) -> 
    Limit = 49*24*60*60, 
    [N rem Limit | lists:duplicate(N div Limit, Limit)]. 

回答

3

它的运行完全在本地机器上,以便防火墙不会影响它。

问题是,当你启动它,你给了第二个参数event:start("Event",0).

错误原因:

{function_clause,[{event,time_to_go,[0],[{file,"event.erl"},{line,48}]},{event,init,3,[{file,"event.erl"},{line,31}]}]} 

说,这是一个function_clause错误,这意味着有一个在功能定义中没有条款这与论据相符。它还告诉你,它是在线48上的功能event:time_to_go/1,它失败了,它被参数0调用。

它你看功能time_to_go/你会看到,它预计它的参数为2个元素的元组,其中每个元素是3个元素的元组:

time_to_go(TimeOut={{_,_,_}, {_,_,_}}) -> 

此参数的结构是{{Year,Month,Day},{Hour,Minute,Second}} 。如果你按照这个论点倒退,你从init/3调用time_to_go/,其中time_to_go/1,DateTime的参数是init/3的第三个参数。现在几乎在那里。现在init/3是该进程中start/2催生了功能(和START_LINK/2 ) and the 3rd argument to的init/3 is the second argument to启动/ 2`。

所以,当你调用event:start("Event",0).这是这里的0被传递到通话time_to_go/1功能的新peocess,而且格式是错误的。你应该像event:start("Event", {{2013,3,24},{17,53,62}}).

+0

这是我的想法(我通过的论点是错误的),但我盲目地遵循网站上的教程,如果你看,你会发现他没有得到任何错误运行它?感谢它现在的作品! – pandoragami 2013-02-10 06:54:00

+0

@lost_with_coding我检查了这本书,对我来说,看起来'0'的调用是第一个版本,其中时间是秒(?)。据我所知,他没有举出第二版日期/时间元组的例子。他应该有的。如果我正确阅读它。 – rvirding 2013-02-12 01:30:16

1

要添加背景rvirding的答案被调用它,你的错误,因为 示例工作,直到最后的代码段就 我所知。首先使用normalize函数,该函数处理 问题。然后在上面的问题 的示例之后的段落,文字说:

它的工作原理!事件模块最后一件烦人的事情是我们 必须输入剩下的秒数。如果我们 可以使用标准格式,比如Erlang的日期时间({{Year, Month, Day}, {Hour, Minute, Second}}),那将会好很多。只需添加下面的函数, 将计算当前时间之间的区别您 计算机上插入的延迟:

下一个片段介绍了码位的是只需要一个日期/时间和 它改变剩下的最后时间。

我无法轻易链接到文件的所有过渡版本,其中 就是为什么在这种情况下直接尝试使用示例链接的文件不起作用 。如果代码按照一步一步进行,代码片段 ,一切都应该正常工作。对困惑感到抱歉。