习惯性的Erlang帮助

时间:2010-06-24 00:02:16

标签: coding-style erlang idiomatic

我在这里有一个Erlang片段,我想研究更多惯用的Erlang,而不是粗略的Python翻译。

进程采用一对全等列表并将它们组合在一起。某些元素需要根据其属性从一个列表或另一个列表中获取,而其余元素需要求和。它运作正常,但我觉得这不是惯用的......

Process = fun([RockA, FishA, TreeA, BarkA, DogA, CowA, MooA, MilkA, CheeseA, BreadA, WineA, GrapesA], [RockB, FishB, TreeB, BarkB, DogB, CowB, MooB, MilkB, CheeseB, BreadB, WineB, GrapesB]) ->
                  if
                      RockA /= [0,0,0] ->
                          NewRock = RockA,
                          NewFish = FishA,
                          NewTree = TreeA,
                          NewBark = BarkA,
                          NewDog = DogA;
                      true ->
                          NewRock = RockB,
                          NewFish = FishB,
                          NewTree = TreeB,
                          NewBark = BarkB,
                          NewDog = DogB
                  end,
                  if
                      CowA > CowB ->
                          NewCow = CowA;
                      true ->
                          NewCow = CowB
                  end,
                  NewMoo = MooA + MooB,
                  NewMilk = MilkA + MilkB,
                  NewCheese = CheeseA + CheeseB,
                  NewBread = BreadA + BreadB,
                  NewWine = WineA + WineB,
                  NewGrapes = GrapesA + GrapesB,
                  [NewRock, NewFish, NewTree, NewBark, NewDog, NewMoo, NewMilk, NewCheese, NewBread, NewWine, NewGrapes];
             (_,_) ->
                  ok
          end.

4 个答案:

答案 0 :(得分:4)

又一个解决方案:

process([RockA, FishA, TreeA, BarkA, DogA | TlA],
        [RockB, FishB, TreeB, BarkB, DogB | TlB]) ->
  case RockA of
    [0,0,0] -> [RockB, FishB, TreeB, BarkB, DogB | process2(TlA, TlB)];
    _       -> [RockA, FishA, TreeA, BarkA, DogA | process2(TlA, TlB)]
  end.

process2([CowA | TlA], [CowB | TlB]) ->
  [erlang:max(CowA, CowB) | process3(TlA, TlB)].

process3([HdA | TlA], [HdB | TlB]) ->
  [HdA + HdB | process3(TlA, TlB)];

process3([], []) -> [].


Process = fun process/2.

答案 1 :(得分:3)

由于列表的压缩和附加,可能不是最有效的版本,但假设它们不会变得更长,与可读性的增益相比,它在大多数程序中都不应该被注意到。

Process = fun([RockA, FishA, TreeA, BarkA, DogA, CowA, | RestA], 
              [RockB, FishB, TreeB, BarkB, DogB, CowB, | RestB]) ->
              Start = if RockA =:= [0,0,0] ->
                            [RockB, FishB, TreeB, BarkB, DogB];
                         true ->
                            [RockA, FishA, TreeA, BarkA, DogA]
                      end,
              Start ++ [max(CowA, CowB)] ++ [X+Y || {X,Y} <- lists:zip(RestA, RestB)]
          end.

当函数调用不匹配时,还要注意缺少catch-all子句。不要写防守代码。让它崩溃并由主管负责。编写防御性代码只会使一个语言中的调试变得更难,因为崩溃不是程序中的死刑。

答案 2 :(得分:1)

以下是一些建议。但是你喜欢中间变量赋值是一个品味问题。请注意'case'和'if'是总是评估某些东西的表达式。我还删除了“() - &gt; ok”catch all;这似乎是在Erlang中不鼓励的防御性编程。

Process = fun([RockA, FishA, TreeA, BarkA, DogA, CowA, MooA, MilkA, CheeseA, BreadA, WineA, GrapesA], 
              [RockB, FishB, TreeB, BarkB, DogB, CowB, MooB, MilkB, CheeseB, BreadB, WineB, GrapesB]) ->

            FirstStuff = case RockA of 
                           [ 0,0,0] ->
                             [RockB, FishB, TreeB, BarkB, DogB];
                           _ ->
                             [RockA, FishA, TreeA, BarkA, DogA]
                         end,

              NewCow = if
                         CowA > CowB -> 
                            CowA;
                         true -> 
                            CowB
                       end,

              lists:flatten( [ FirstStuff,
                               NewCow,
                               MooA + MooB,
                               MilkA + MilkB,
                               CheeseA + CheeseB,
                               BreadA + BreadB,
                               WineA + WineB,
                               GrapesA + GrapesB ]);
          end.

甚至......

Process = fun([RockA, FishA, TreeA, BarkA, DogA, CowA, MooA, MilkA, CheeseA, BreadA, WineA, GrapesA], 
              [RockB, FishB, TreeB, BarkB, DogB, CowB, MooB, MilkB, CheeseB, BreadB, WineB, GrapesB]) ->

              lists:flatten( [ case RockA of 
                                 [ 0,0,0] ->
                                   [RockB, FishB, TreeB, BarkB, DogB];
                                 _ ->
                                   [RockA, FishA, TreeA, BarkA, DogA]
                               end,
                               lists:max([CowA,CowB]),
                               MooA + MooB,
                               MilkA + MilkB,
                               CheeseA + CheeseB,
                               BreadA + BreadB,
                               WineA + WineB,
                               GrapesA + GrapesB ]);
          end.

答案 3 :(得分:1)

或者,采用Zed的答案并用函数子句替换案例,我们可以执行以下操作。我们找到了惯用的吗?大部分都是品味和审美的问题。

process([[0,0,0], _, _, _, _ | TlA],
        [RockB, FishB, TreeB, BarkB, DogB | TlB]) ->
    [RockB, FishB, TreeB, BarkB, DogB | process2(TlA, TlB)];

process([RockA, FishA, TreeA, BarkA, DogA | TlA],
        [_, _, _, _, _ | TlB]) ->
    [RockA, FishA, TreeA, BarkA, DogA | process2(TlA, TlB)].

process2([CowA | TlA], [CowB | TlB]) ->
  [erlang:max(CowA, CowB) | process3(TlA, TlB)].

process3([HdA | TlA], [HdB | TlB]) ->
  [HdA + HdB | process3(TlA, TlB)];

process3([], []) -> [].


Process = fun process/2.