【问题标题】:Overuse of guards in Erlang?Erlang 中过度使用守卫?
【发布时间】:2012-05-22 22:24:36
【问题描述】:

我有以下函数,它接受一个像 5 这样的数字并创建一个从 1 到该数字的所有数字的列表,所以 create(5)。返回 [1,2,3,4,5]。

我认为我已经过度使用了警卫,并且想知道是否有更好的方法来编写以下内容:

create(N) ->
    create(1, N).

create(N,M) when N =:= M ->
    [N];
create(N,M) when N < M ->
    [N] ++ create(N + 1, M).

【问题讨论】:

  • 你可以看看lists:seq的源码,看看它是如何实现的。
  • 一般来说,守卫是相当有效的。尝试对不同版本进行基准测试:trapexit.org/Measuring_Function_Execution_Time 有时,具有更多保护的版本会更快,因为编译器使用您提供的额外信息进行了优化。

标签: erlang


【解决方案1】:

N &lt; M 的守卫可能很有用。一般来说,你不需要平等的守卫。你可以使用模式匹配。

create(N) -> create(1, N).

create(M, M) -> [M];
create(N, M) when N < M -> [N | create(N + 1, M)].

您通常还希望将函数编写成尾递归的,其中一般的习惯用法是先写入头部,然后在末尾反转。

create(N) -> create(1, N, []).

create(M, M, Acc) -> lists:reverse([M | Acc]);
create(N, M, Acc) when N < M -> create(N + 1, M, [N | Acc]).

(当然,对于这个特定的示例,您也可以按相反的顺序构建结果,从 1 到 M,这将使lists:reverse 调用变得不必要。)

如果create/2(或create/3)未导出,并且您在create/1 上设置了适当的保护,则额外的N &lt; M 保护可能会过大。我通常只检查导出的函数并信任我自己的内部函数。

【讨论】:

    【解决方案2】:
    create(N,N) -> [N];
    create(N,M) -> [N|create(N + 1, M)]. % Don't use ++ to prefix a single element.
    

    这并不完全相同(您可以提供 -5),但如果您提供有意义的输入,它的行为是相同的。无论如何,我不会为额外的检查而烦恼,因为无论哪种方式,该过程都会很快崩溃。

    顺便说一句,您的代码原样存在递归深度问题。这将解决它:

    create(N) ->
        create(1, N, []).
    
    create(N, N, Acc) -> [N|Acc];
    create(N, M, Acc) -> create(N, M - 1, [M|Acc]).
    

    【讨论】:

      【解决方案3】:

      我真的不认为你过度使用警卫。有两种情况:

      首先是create/2第一个子句中的显式相等测试

      create(N, M) when N =:= M -> [M];
      

      有些人建议将其转换为使用模式匹配,例如

      create(N, N) -> [N];
      

      在这种情况下,编译器会在内部将模式匹配版本转换为您编写的版本,因此没有区别。您可以放心地选择您认为在每种情况下感觉最好的版本。

      在第二种情况下,您需要某种形式的健全性检查,以确保参数的值在您期望的范围内。在每个循环中都做是不必要的,我会将其移至 create/1 中的等效测试:

      create(M) when M > 1 -> create(1, M).
      

      如果你想使用累加器,我个人会使用 count 版本,因为它可以在最后保存反转列表。如果列表不长,我认为差异很小,您可以选择您感觉最清楚的版本。无论如何,如果您发现它很关键,以后很容易更改。

      【讨论】:

        猜你喜欢
        • 2015-05-15
        • 1970-01-01
        • 1970-01-01
        • 2011-10-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多