【问题标题】:novice question - should one use ifs or short functions when programming erlang?新手问题 - 在编写 erlang 时应该使用 ifs 还是短函数?
【发布时间】:2011-03-08 21:06:23
【问题描述】:

我最近开始认真学习 Programming Erlang 这本书,我有一个问题。 以下是 Erlang 的正确方法吗?这是(为简洁而修改(无退出消息),在基本验证后删除日志记录)解决来自 ch4 的环问题。进程在传递消息预期次数后退出;第一个进程等待最后一条消息到达并退出。

除了对风格和实质的一般批评之外,你能告诉我这样写特殊的 1-2 行函数是否是正确的风格,或者是否应该使用 if-s、cases-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.

【问题讨论】:

    标签: erlang


    【解决方案1】:

    我觉得你的风格很好很简洁!干得好!

    几个cmets(个人口味):

    • 起始环可以改写为:

      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:我不喜欢在带有多个子句的函数之间使用换行符。这使得查看函数的开始和结束位置变得更加困难。然后可以将 cmets 放在子句主体内部而不是外部。现在更容易识别函数头(并将函数视为一个单元):

      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(也将它们用于第一个子句,这是额外的文档!)

    【讨论】:

      【解决方案2】:

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

      嵌套代码是包含 case/if/receive 语句 其他 case/if/receive 语句。它 编写不好的编程风格 深度嵌套的代码——代码有一个 倾向于在页面上漂移到 权利并很快变得不可读。 尝试将大部分代码限制为 最多两级缩进。 这可以通过划分 将代码转换为更短的函数。

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

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

      "总是使用大小写,if 结构 有点坏了”。

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

      可能重复:

      Erlang style - case vs function pattern matching

      【讨论】:

        猜你喜欢
        • 2010-12-08
        • 1970-01-01
        • 2016-01-25
        • 2021-02-22
        • 2016-11-30
        • 2012-05-25
        • 2010-12-10
        • 2018-06-13
        • 1970-01-01
        相关资源
        最近更新 更多