4 Stimmen

Übermäßiger Gebrauch von Guards in Erlang?

Ich habe die folgende Funktion, die eine Zahl wie 5 nimmt und erstellt eine Liste aller Zahlen von 1 bis diese Zahl so create(5). gibt [1,2,3,4,5].

Ich denke, ich habe zu viele Wachen eingesetzt und frage mich, ob es eine bessere Möglichkeit gibt, das Folgende zu schreiben:

create(N) ->
    create(1, N).

create(N,M) when N =:= M ->
    [N];
create(N,M) when N < M ->
    [N] ++ create(N + 1, M).

6voto

Tadmas Punkte 6030

Der Wächter für N < M kann nützlich sein. Im Allgemeinen brauchen Sie keinen Guard für Gleichheit; Sie können Pattern-Matching verwenden.

create(N) -> create(1, N).

create(M, M) -> [M];
create(N, M) when N < M -> [N | create(N + 1, M)].

Außerdem sollten Sie Funktionen im Allgemeinen so schreiben, dass sie "tail-recursive" sind, d. h., dass sie in den Kopf geschrieben werden und dann am Ende umgekehrt.

create(N) -> create(1, N, []).

create(M, M, Acc) -> lists:reverse([M | Acc]);
create(N, M, Acc) when N < M -> create(N + 1, M, [N | Acc]).

(Natürlich können Sie in diesem speziellen Beispiel die Ergebnisse auch in umgekehrter Reihenfolge aufbauen, indem Sie von unten nach 1 statt von oben nach M gehen, wodurch die lists:reverse Anruf unnötig).

Si create/2 (o create/3 ) nicht exportiert wird und Sie einen entsprechenden Schutz für create/1 das Extra N < M Wache könnte zu viel des Guten sein. Ich überprüfe im Allgemeinen nur die exportierten Funktionen und vertraue meinen eigenen internen Funktionen.

4voto

Marcelo Cantos Punkte 173498
create(N,N) -> [N];
create(N,M) -> [N|create(N + 1, M)]. % Don't use ++ to prefix a single element.

Das ist nicht ganz dasselbe (man könnte -5 eingeben), aber es verhält sich genauso, wenn man sinnvolle Eingaben macht. Ich würde mir die Mühe mit der zusätzlichen Prüfung sowieso nicht machen, da der Prozess so oder so sehr schnell abstürzen wird.

BTW, haben Sie eine Rekursionstiefe Problem mit dem Code wie es ist. Dies wird es beheben:

create(N) ->
    create(1, N, []).

create(N, N, Acc) -> [N|Acc];
create(N, M, Acc) -> create(N, M - 1, [M|Acc]).

1voto

rvirding Punkte 20550

Ich glaube nicht, dass Sie zu viele Wachen eingesetzt haben. Es gibt zwei Fälle:

Der erste ist der explizite Gleichheitstest in der ersten Klausel von create/2

create(N, M) when N =:= M -> [M];

Einige haben vorgeschlagen, dies umzuwandeln, um Mustervergleiche zu verwenden wie

create(N, N) -> [N];

In diesem Fall macht es keinen Unterschied, da der Compiler die Version mit Mustervergleich intern in das umwandelt, was Sie geschrieben haben. Sie können ohne Bedenken die Version wählen, die Sie in jedem Fall für die beste halten.

Im zweiten Fall brauchen Sie eine Art von Sicherheitsprüfung, dass der Wert des Arguments in dem Bereich liegt, den Sie erwarten. Doing in jeder Schleife ist unnötig und ich würde es zu einem gleichwertigen Test in create/1 verschieben:

create(M) when M > 1 -> create(1, M).

Wenn Sie einen Akkumulator verwenden möchten, würde ich persönlich die Zählversion verwenden, da sie das Umkehren der Liste am Ende erspart. Wenn die Liste nicht lang ist, denke ich, dass der Unterschied sehr gering ist und Sie die Version wählen können, die Ihnen am klarsten erscheint. Auf jeden Fall ist es sehr einfach, dies später zu ändern, wenn Sie es für kritisch halten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X