2009-06-28 5 views
4

私はthis questionにつまずいたので、私は無手順プログラミングクラスからたくさんのものを忘れてしまったことに気付きました。erlangと関数型プログラミングに関する重要でない質問

私はコードを理解しようとしていたので、それはひどく長続きしていると思われたので、私はそれを短縮しようとしました。これは元のコードと同じことをしますか?

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

...私は前にアーランで働いたことがありませんので、私は多分はい、それは正常に動作

答えて

3

:-)いくつかの構文エラーをしました。そしてそれはプレゼンテーションでよりエレガントです。しかし、私が正しく学習した場合、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)に別の名前を付けることも良い習慣です。これは、アリティの変化を見つけるのが簡単です。これは特に、merge/2がエクスポートされず、merge1/3がエクスポートされていない場合に当てはまります。それは基本的に "私はちょうどヘルパーfnは私を直接電話していないよ!

これは、再帰の性質を明示的にするので、最初に目的のターミネータ節を書くと便利です。このfnがリスト消耗で終わる関数定義を読めばすぐにわかります。

+0

リストを空のリストにマージすると、このコードは元のリストを返しますか?パターンマッチングは私には見えません。 –

+0

元のタスクは同じ長さの2つのリストのためのものでした – cube

+0

キューブが正しい - そしてあなたが不等長さの2つのリストで元のコードを実行しようとすると失敗するでしょう。 mergeR([]、[]、Zs)に一致する終端節XsとYsの長さが異なる場合、一方のリストがもう一方のリストの前に使い果たされるとエラーになります。 –

関連する問題