休假回来,调整一下状态,先把Evernote里面一些比较零散的东西整理出来;过去一个月对于Erlang开发者还是有些惊喜的,比如Erlang/OTP并发编程实战》终于出版了;比如<Building.Web.Applications.with.Erlang>也可以看到英文版了.下面第一条消息就是关于Erlang的另外一本好书:Learn You Some Erlang

 

Learn You Some Erlang 两则

  Erlang学习有一个非常棒的网站: http://learnyousomeerlang.com/

  现在有两则关于它的消息:

   [1] 首先是这本书的Kindle版本, 能够在移动设备上阅读这本书,真的是非常方便;其实不仅仅是Kindle 其它支持mobi格式的都可以完美显示;甚至你可以使用源文件自己编译成为其它格式,比如epub;

    github地址:https://github.com/igstan/learn-you-some-erlang-kindle

  [2] 这个网站的出版物已经发行,其中文版由 @淘宝褚霸 翻译,可以预见到这又将成为中文资料的经典之作

   http://book.douban.com/subject/10822017/

 

 

string To Erlang Term 一个更为考虑更为完善的方法

下面是可以解决的:

1> E=fun(S) ->{ok,Scanned,_} = erl_scan:string(S),
{ok,Parsed} = erl_parse:parse_exprs(Scanned),
erl_eval:exprs(Parsed,[]) end.
#Fun<erl_eval.6.111823515>
2> E("{quit,tom}\n"++".").
{value,{quit,tom},[]}
3>

如果是Pid的情况下会存在异常

** exception error: no match of right hand side value

                    {error,{1,erl_parse,["syntax error before: ","'<'"]}} 

然后我在这里发现了一个更为完善的做法

https://github.com/erlang/otp/blob/master/lib/tv/src/tv_db_search.erl

string_to_term(Str) ->
    case catch erl_scan:string(Str ++ ". ") of
     {ok, ScannedStr, _No} ->
         case erl_parse:parse_term(ScannedStr) of
          {ok, Term} ->
              {ok, Term};
          _Other ->
                 %% May be a PID, have to check this, since erl_scan
                 %% currently cannot handle this case...  :-(
              case catch list_to_pid(Str) of
               Pid when is_pid(Pid) ->
                   {ok, Pid};
               _Error ->
                   case get(error_msg_mode) of
                    normal ->
                        {error, {not_a_term, "Please enter a valid term!"}};
                    haiku ->
                        {error, {not_a_term, ["Aborted effort.",
                                     "Reflect, repent and retype:",
                                     "Enter valid term."]}}
                   end
              end
         end;
     _Error ->
         case get(error_msg_mode) of
          normal ->
              {error, {not_a_term, "Please enter a valid term!"}};
          haiku ->
              {error, {not_a_term, ["Aborted effort.",
                           "Reflect, repent and retype:",
                           "Enter valid term."]}}
         end
    end. 

 

binary 替换一例 注意转义符的使用

这个没有什么特别的,只是要注意转义字符的使用

85> binary:replace(<<"c:\\windows\\abc\\c.txt">>,<<92>>,<<"//">>,[global]).
<<"c://windows//abc//c.txt">>
86> binary:replace(<<"c:\\windows\\abc\\c.txt">>,<<"\\">>,<<"//">>,[global]).
<<"c://windows//abc//c.txt">>
87> 

 

ETS表中,根据表名获取ets表id,可用但是繁琐一点

 

12> Fun3=fun(Name)->[ ID|| ID <-ets:all(),Name==ets:info(ID,name)] end.

#Fun<erl_eval.6.111823515>

13> Fun3(inet_db).

[inet_db]

14> Fun3(code).

"\r"

15> Fun3(code_names).

[4110]

16>

 

 多个条件组合判断代码风格 2012-11-08 13:34 更新

  多个条件的组合判断容易case套case 嵌套很多层 ,在Rabbitmq上看到一种代码风格比较不错 

 

 %% Wipe mnesia if we're changing type from disc to ram
    case {is_disc_node(), should_be_disc_node(ClusterNodes)} of
        {true, false} -> rabbit_misc:with_local_io(
                           fun () -> error_logger:warning_msg(
                                       "changing node type; wiping "
                                       "mnesia...~n~n")
                           end),
                         rabbit_misc:ensure_ok(mnesia:delete_schema([node()]),
                                               cannot_delete_schema);
        _             -> ok
    end,

 

 

 

erlang模块下面有一个非常好用的解包方法

下面的解析可以使用string或binary模块自行解析,其实使用erlang:packet直接可以得到结果

 

Eshell V5.9.1  (abort with ^G)
1> erlang:decode_packet(http,<<"GET http://www.google.com HTTP/1.1\n">>,[]).
{ok,{http_request,'GET',
                  {absoluteURI,http,"www.google.com",undefined,"/"},
                  {1,1}},
    <<>>}
2> erlang:decode_packet(1,<<3,"abcd">>,[]).
{ok,<<"abc">>,<<"d">>}
3>  erlang:decode_packet(1,<<5,"abcd">>,[]).
{more,6}
4>

 

erlang:decode_packet的官方文档地址:http://www.erlang.org/doc/man/erlang.html

 

Erlang字符串处理的两个开源项目

[1] http://code.google.com/p/starling/

Unicode strings for Erlang

 

Starling is a Unicode string library for Erlang based on ICU, the best implementation of Unicode.

 

It's implemented as a C pipe driver packaged as an OTP application. Strings are stored as binaries internally. Compatibility layer with the standard string module is provided.

 

A mailing list has been set up at http://groups.google.com/group/starling-discuss.

 

The project homepage is at http://12monkeys.co.uk/starling.

[2]https://github.com/beerriot/icu4e icu4e: Erlang NIF wrappers around icu4c

 



Erlang异常处理:error exit throw
 
     调用erlang:error(Reason)会中断当前进程的执行最后执行函数的堆栈信息.当方法执行过程中出现处理不了的情况的时候后就应该使用error来停止方法的执行.
 
Eshell V5.9  (abort with ^G)
1> self().
<0.30.0>
2> erlang:error(test_not_ok).
** exception error: test_not_ok
3> self().
<0.33.0>
4> catch erlang:error(test_not_ok).
{'EXIT',{test_not_ok,[{erl_eval,do_apply,6,
                                [{file,"erl_eval.erl"},{line,576}]},
                      {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,360}]},
                      {shell,exprs,7,[{file,"shell.erl"},{line,668}]},
                      {shell,eval_exprs,7,[{file,"shell.erl"},{line,623}]},
                      {shell,eval_loop,3,[{file,"shell.erl"},{line,608}]}]}}
 
Exit
  用于进程级别处理异常消息,exit/1和erlang:error的效果等同但是erlang:error会包含堆栈信息,这有好有坏,好处是信息量增加帮助判断,坏处是在堆栈信息庞大的情况下,会造成堆栈信息拷贝的成本.
  
Throw
  并不包含让进程终止执行的意图,所以可以用作控制流.throw非常典型的使用场景还可以从深度递归程序中跳出. 可以把Throw当作return来用,不过在团队内部明确并记录约定很重要
 
validate_inet_option(mode, Value)
  when Value =/= list, Value =/= binary ->
    throw({error, {eoptions, {mode,Value}}});
validate_inet_option(packet, Value)
  when not (is_atom(Value) orelse is_integer(Value)) ->
    throw({error, {eoptions, {packet,Value}}});
validate_inet_option(packet_size, Value)
  when not is_integer(Value) ->
    throw({error, {eoptions, {packet_size,Value}}});
validate_inet_option(header, Value)
  when not is_integer(Value) ->
    throw({error, {eoptions, {header,Value}}});
validate_inet_option(active, Value)
  when Value =/= true, Value =/= false, Value =/= once ->
    throw({error, {eoptions, {active,Value}}});
validate_inet_option(_, _) ->
    ok. 
 
下面是erlang:error和throw比较典型的使用示例,选自\erl5.9\lib\stdlib-1.18\src\array.erl
 
-spec reset(I :: array_indx(), Array :: array()) -> array().

reset(I, #array{size = N, max = M, default = D, elements = E}=A) 
    when is_integer(I), I >= 0 ->
    if I < N ->
         try A#array{elements = reset_1(I, E, D)} 
         catch throw:default -> A
         end;
       M > 0 ->
         A;
       true ->
         erlang:error(badarg)
    end;
reset(_I, _A) ->
    erlang:error(badarg).

reset_1(I, E=?NODEPATTERN(S), D) ->
    I1 = I div S + 1,
    setelement(I1, E, reset_1(I rem S, element(I1, E), D));
reset_1(_I, E, _D) when is_integer(E) ->
    throw(default);
reset_1(I, E, D) ->
    Indx = I+1,
    case element(Indx, E) of
     D -> throw(default);
     _ -> setelement(I+1, E, D)
    end.

 

2012-08-30 17:25更新 

http://learnyousomeerlang.com/errors-and-exceptions

Note: It is important to know that the protected part of an exception can't be tail recursive. The VM must always keep a reference there in case there's an exception popping up.

Because the try ... catch construct without the of part has nothing but a protected part, calling a recursive function from there might be dangerous for programs supposed to run for a long time (which is Erlang's niche). After enough iterations, you'll go out of memory or your program will get slower without really knowing why. By putting your recursive calls between the of and catch, you are not in a protected part and you will benefit from Last Call Optimisation.

Some people use try ... of ... catch rather than try ... catch by default to avoid unexpected errors of that kind, except for obviously non-recursive code with a result they don't care about. You're most likely able to make your own decision on what to do!

 

2012-09-06 更新
有个朋友"有四个分组,每个分组独立统计得分然后排行",这个有没有简单的做法?这个功能其实很容易实现,但他所定义的简单其实就是能不能用一两行代码实现,下面这两行矫揉造作的代码就可以实现他的需要,但是!但是这样写没有任何优势,一旦逻辑复杂或者想添加调试就让这个方法特别的庞杂,大多数时候我们还是要按照规矩的路子写代码.
 
L=[{30,a},{40,b},{30,a},{40,b},{23,c},{12,c},{1,d},{100,d}].
 
lists:foldl(fun({X,a}, [{A,a},{B,b},{C,c},{D,d}]) -> [{A+X,a},{B,b},{C,c},{D,d}] ; ({X,b},[{A,a},{B,b},{C,c},{D,d}])->[{A,a},{B+X,b},{C,c},{D,d}] ;({X,c},[{A,a},{B,b},{C,c},{D,d}])->[{A,a},{B,b},{C+X,c},{D,d}] ;({X,d},[{A,a},{B,b},{C,c},{D,d}])->[{A,a},{B,b},{C,c},{D+X,d}]    end,   [{0,a},{0,b},{0,c},{0,d}],L).
 
 
2012-11-5 20:41:58更新
  虽然大部分调试都是在Centos完成,但是在windows中还是有运行的需求,有一个非常不方便的事情就是如何让erlang运行主目录设置为当前目录,我通常用下面的方法:
 在当前目录添加一个erl.cmd的文件,里面只需要一句""c:\Program Files\erl5.8.2\bin\erl.exe" -sname n1",如果你已经将erlang配置到环境变量,就更简单了,只需要三个字母"erl"即可.
 
 今天在Ulf wiger博客学了一招:设置.erl的打开方式为erl.exe,然后双击任何一个文件就可以打开Erlang Shell,且pwd()一下发现,已经在当前目录了.