неважный вопрос об эрланге и функциональном программировании - PullRequest
4 голосов
/ 28 июня 2009

Я наткнулся на этот вопрос и понял, что забыл много вещей из своего класса непроцедурного программирования.

Когда я пытался понять код, мне показалось, что он ужасно многословен, поэтому я попытался его сократить. Делает ли это то же самое, что и оригинальный код?

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

... Раньше я никогда не работал с erlang, поэтому я допустил некоторые синтаксические ошибки: -)

Ответы [ 2 ]

3 голосов
/ 28 июня 2009

Да, работает правильно. И это более элегантно в представлении. Однако, если я правильно понял, отсутствие использования переменной Zs в качестве аккумулятора делает ее нерекурсивной и, следовательно, менее эффективной. Кроме того, использование реверса с аккумулятором более эффективно, чем сложение его в правильном порядке. Вот почему я считаю, что оригинал был бы в некоторых случаях более правильным. Но удобочитаемость должна превосходить эффективность там, где эффективность не имеет значения.

Может быть:

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

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

Это объединит эффективность оригинала с вашей краткой понятностью.

2 голосов
/ 28 июня 2009

Вы можете пойти дальше:

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) другого имени, так как это легче обнаружить при изменении арности. Это особенно верно, если, например, merge / 2 не экспортируется, а merge1 / 3 нет. Это в основном говорит: «Я просто помощник, не называй меня прямым!»

Также удобно сначала написать желаемое предложение-терминатор, поскольку это делает природу рекурсии явной - как только вы прочитаете определение функции, этот fn завершается при исчерпании списка.

...