views:

170

answers:

2

I stumbled upon this question and i realized i forgot a lot of stuff from my nonprocedural programming class.

As I was trying to understand the code it seemed to me that it's terribly long-winded, so i attempted to shorten it. Does this do the same thing that the original code does?

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

... I've never worked with erlang before, so i maybe made some syntax errors :-)

+3  A: 

Yes, it works properly. And it is more elegant in presentation. However, if I've learned correctly, not using the Zs variable as an accumulator makes it not tail recursive and thus less efficient. Also, using the reverse with the accumulator is more efficient than appending it together in correct order. This is, I believe, why the original would be in some cases more proper. But readability should trump efficiency where efficiency doesn't matter.

Perhaps:

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

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

This would merge the efficiency of the original with the concise comprehensibility of yours.

Kim Reece
+2  A: 

You could go further:

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

merge1([], [], Zs)             -> Zs.
merge1([X | Xs], [Y | Ys], Zs) -> merge1(Xs, Ys, [X, Y | Zs]).

This has the considerable advantage over feonixrift's suggestion that you are not switching the parameter order (which violates the principle of least surprise).

It is also good practice to give the helper function (in this case merge1) a different name as this is easier to spot that a change in arity. This is particularly true if, for instance merge/2 isn't exported and merge1/3 isn't. It basically says "I'm just a helper fn don't call me direct!"

It is also handy to write the desired terminator clause first as this makes the nature of the recursion explicit - you know as soon as you read the function definition that this fn terminates on list exhaustion.

Gordon Guthrie
If I merge a list with the empty list, will this code return the original list? The pattern matching doesn't look complete to me.
Nathan Sanders
the original task was for two lists of the same length
cube
cube is right - and if you tried to run the original code on two lists of unequal length it would fail. The terminal clause there matches on mergeR([], [], Zs) If Xs and Ys were of different lengths it would error out as one list exhausted before the other.
Gordon Guthrie