【问题标题】:unimportant question about erlang and functional programming关于 erlang 和函数式编程的不重要问题
【发布时间】:2010-11-06 12:19:39
【问题描述】:

我偶然发现了this question,我意识到我在我的非过程编程课上忘记了很多东西。

当我试图理解代码时,我觉得它非常冗长,所以我试图缩短它。这和原始代码做的事情一样吗?

merge([X|Xs], Ys) -> [X | merge(Ys, Xs)];
merge([], []) -> [].

...我以前从未使用过 erlang,所以我可能犯了一些语法错误:-)

【问题讨论】:

    标签: functional-programming erlang


    【解决方案1】:

    是的,它工作正常。并且在呈现上更加优雅。但是,如果我学得正确,不使用 Zs 变量作为累加器会使其不是尾递归,因此效率较低。此外,与累加器一起使用反向比以正确的顺序将其附加在一起更有效。我相信,这就是为什么原版在某些情况下会更合适的原因。但在效率无关紧要的情况下,可读性应该胜过效率。

    也许:

    merge(Xs, Ys) -> lists:reverse(merge(Xs, Ys, [])).
    
    merge([X|Xs], Ys, Zs) -> merge(Ys, Xs, [X|Zs]);
    merge([], [], Zs) -> Zs.
    

    这会将原文的效率与您的简洁易懂性结合起来。

    【讨论】:

      【解决方案2】:

      你可以走得更远:

      merge(Xs, Ys) -> lists:reverse(merge1(Xs, Ys, [])).
      
      merge1([], [], Zs)             -> Zs.
      merge1([X | Xs], [Y | Ys], Zs) -> merge1(Xs, Ys, [X, Y | Zs]).
      

      这比 feonixrift 建议您不要切换参数顺序(这违反了最小意外原则)具有相当大的优势。

      给辅助函数(在本例中为merge1)一个不同的名称也是一个好习惯,因为这样更容易发现arity 的变化。例如,如果没有导出 merge/2 而没有导出 merge1/3,则尤其如此。它基本上说“我只是一个帮手,不要直接打电话给我!”

      首先编写所需的终止子句也很方便,因为这使递归的性质变得明确 - 只要您阅读函数定义,您就知道这个 fn 在列表耗尽时终止。

      【讨论】:

      • 如果我将一个列表与空列表合并,此代码会返回原始列表吗?模式匹配在我看来并不完整。
      • 原来的任务是两个相同长度的列表
      • cube 是正确的 - 如果您尝试在两个长度不等的列表上运行原始代码,它将失败。那里的终端子句匹配 mergeR([], [], Zs) 如果 Xs 和 Ys 的长度不同,则会出错,因为一个列表先于另一个列表用尽。
      猜你喜欢
      • 2021-12-23
      • 2020-05-16
      • 1970-01-01
      • 2010-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-22
      • 1970-01-01
      相关资源
      最近更新 更多