新手问题 - 在编写erlang时应该使用ifs还是short函数?

时间:2011-03-08 08:22:32

标签: erlang

我最近认真研究了Erlang编程,我有一个问题。 以下是Erlang的正确方法吗?这是(为了简洁而修改(没有退出消息),在基本验证后删除了日志)从ch4解决了环问题。进程在传递预期的消息次数后退出;第一个进程等待最后一条消息到达并退出。

除了对风格和内容的一般批评之外,你能不能告诉我,如果写这样一个特殊的1-2行函数是正确的风格,还是应该使用if-s,case-s等?

start_ring( 0, _, _ ) -> {error, badarg};
start_ring( _, 0, _ ) -> {error, badarg};
start_ring( M, N, Message ) -> 
    spawn( ring, run_ring, [M, N, Message, 0] ).

% last process that connects the ring 
run_ring( M, 1, Message, Pid ) when is_pid(Pid) -> 
    loop_ring( M, Message, Pid, false );

% process in the middle
run_ring( M, N, Message, Pid ) when is_pid(Pid) ->
    loop_ring( M, Message, spawn( ring, run_ring, [M, N-1, Message, Pid] ), false );

% first process - special case for one process
run_ring( M, 1, Message, _ ) -> 
    loop_ring( M, self() ! Message, self(), true );

% first process 
run_ring( M, N, Message, _ ) -> 
    NextPid = spawn( ring, run_ring, [M, N-1, Message, self()] ),
    loop_ring( M, NextPid ! Message, NextPid, true ).

loop_ring( 0, _, _, _ ) -> ok;

loop_ring( 1, Message, Next, true ) -> ok;

loop_ring( M, Message, Next, IsMaster ) ->
    receive 
        Message -> loop_ring( M - 1, Next ! Message, Next, IsMaster )
    end.

2 个答案:

答案 0 :(得分:7)

我认为你的风格非常简洁!干得好!

一些评论(个人品味):

  • 开始响铃可以改写为:

    start_ring( M, N, Message ) when M < N, N > 0, M > 0 -> 
       spawn( ring, run_ring, [M, N, Message, 0] ).
    

    如果使用不当,这将导致function_clause错误。处理错误返回时有一个好习惯,即如果用户可以对错误做一些合理的事情,则返回例如{error, Reason},否则只是崩溃。我认为在这种情况下,崩溃是安全的,因为任何其他输入都是程序中的错误。

  • run_ring/4 + loop_ring/4:我不喜欢在具有多个子句的函数之间使用换行符。这使得更难以看到函数的开始和结束位置。然后可以将注释放在子句体内而不是外部。现在识别函数头更容易(并将函数看作一个单元):

    run_ring(M, 1, Message, Pid) when is_pid(Pid) ->
        % last process that connects the ring
        loop_ring(M, Message, Pid, false);
    run_ring(M, N, Message, Pid) when is_pid(Pid) ->
        % process in the middle
        loop_ring(M, Message, spawn(ring, run_ring, [M, N-1, Message, Pid]), false);
    run_ring(M, 1, Message, _) ->
        % first process - special case for one process
        loop_ring(M, self() ! Message, self(), true);
    run_ring(M, N, Message, _) ->
        % first process
        NextPid = spawn(ring, run_ring, [M, N-1, Message, self()]),
        loop_ring(M, NextPid ! Message, NextPid, true).
    
  • 我个人不喜欢括号内的空格(正如我所说,个人品味)。 :-)使代码更“蓬松”。

  • 使用spawn_link/3代替spawn/3,除非您知道自己不需要它。在开发程序时,它可以更容易地检测错误等。

  • loop_ring/4的第二个子句会发出编译器警告。请改用_Message_Next(也可以将它们用于第一个条款,这是奖金文档!)

答案 1 :(得分:3)

根据Erlang best practices,应该避免ifcase嵌套两次以上:

  

嵌套代码是包含的代码   case / if / receive语句   其他案例/ if / receive语句。它   编写风格很糟糕   深层嵌套代码 - 代码有一个   倾向于跨越页面   正确的,很快变得难以理解。   尝试将大部分代码限制为a   最多两个缩进级别。   这可以通过划分来实现   将代码转换为更短的函数。

除此之外,我想使用if/case或简单的模式匹配是一种品味问题。就个人而言,我更喜欢使用模式匹配而不是if或case。所以,如果你问我,你会以正确的方式做到这一点。

关于ifcase,通常可以将前者重写为后者。有人说:

  

“总是使用case,if构造   有点破碎“。

嗯,这两个结构的工作方式完全不同。在if构造中评估的表达式是一个守护者并且它有很多限制 - 因为你不能对守卫产生副作用,而不考虑所采取的分支进行评估。案例构造没有这种“限制”。你可以在那里使用任何表达式,其结果将与形成案例的模式相匹配。

可能重复:

Erlang style - case vs function pattern matching