2009-06-28 5 views
4

Ich stolperte über this question und ich erkannte, dass ich eine Menge Sachen aus meiner nicht prozeduralen Programmierklasse vergessen habe.unwichtige Frage über Erlang und funktionale Programmierung

Als ich versuchte, den Code zu verstehen, schien es mir, dass es schrecklich langatmig ist, also versuchte ich, es zu verkürzen. Macht dies das Gleiche wie der ursprüngliche Code?

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

... Ich habe noch nie zuvor gearbeitet mit erlang, so dass ich vielleicht einige Syntaxfehler :-)

Antwort

3

Ja, es richtig funktioniert. Und es ist eleganter in der Präsentation. Wenn ich jedoch richtig gelernt habe, macht die Verwendung der Zs-Variablen als Akkumulator sie nicht rekursiv und damit weniger effizient. Außerdem ist es effizienter, die Umkehrung mit dem Akkumulator zu verwenden, als sie in der richtigen Reihenfolge zusammenzufügen. Das ist, glaube ich, der Grund, warum das Original in einigen Fällen angemessener wäre. Aber Lesbarkeit sollte Effizienz übertrumpfen, wo Effizienz keine Rolle spielt.

Vielleicht:

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

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

Dies würde die Effizienz des Originals mit der prägnanten Nachvollziehbarkeit von Ihnen verschmelzen.

2

Man könnte noch weiter gehen:

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

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

Dies hat den erheblichen Vorteil gegenüber feonixrift Vorschlag, dass Sie nicht den Parameter, um Schalt (die das Prinzip der geringsten Überraschung verletzt).

Es ist auch eine gute Übung, der Hilfsfunktion (in diesem Fall merge1) einen anderen Namen zu geben, da dies leichter eine Änderung der Arity erkennen lässt. Dies ist insbesondere dann der Fall, wenn zum Beispiel merge/2 nicht exportiert wird und merge1/3 nicht exportiert wird. Es sagt im Grunde "Ich bin nur ein Helfer fn rufen Sie mich nicht direkt an!"

Es ist auch praktisch, die gewünschte Terminatorklausel zuerst zu schreiben, da dies die Art der Rekursion explizit macht - Sie wissen, sobald Sie die Funktionsdefinition gelesen haben, dass diese Fn bei Erschöpfung der Liste endet.

+0

Wenn ich eine Liste mit der leeren Liste zusammenführe, gibt dieser Code die ursprüngliche Liste zurück? Der Mustervergleich sieht für mich nicht vollständig aus. –

+0

die ursprüngliche Aufgabe war für zwei Listen der gleichen Länge – cube

+0

Cube ist richtig - und wenn Sie versuchten, den ursprünglichen Code auf zwei Listen ungleicher Länge zu laufen, würde es scheitern. Die Endungsklausel dort stimmt mit mergeR ([], [], Zs überein) Wenn Xs und Ys unterschiedliche Längen hatten, würde es sich als eine Liste ausgeben, die vor der anderen erschöpft ist. –