关于erlang和函数式编程的重要问题

时间:2009-06-28 16:36:57

标签: functional-programming erlang

我偶然发现了this question,我意识到我从非程序设计课程中忘记了很多东西。

当我试图理解代码时,我觉得它非常啰嗦,所以我试图缩短它。这是否与原始代码的作用相同?

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

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

2 个答案:

答案 0 :(得分:3)

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

也许:

merge(Xs, Ys) -> lists:reverse(merge(Xs, Ys, [])).

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

这会将原作的效率与你的简洁可理解性结合起来。

答案 1 :(得分: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就会在列表耗尽时终止。