2009-07-14 17 views
9

Sto scrivendo una funzione di Erlang che stampa ogni numero pari fino ad un dato parametro.In Erlang, c'è un modo per creare una funzione vuota?

Finora, ho scritto la funzione con le guardie in questo modo:

printEven(I,N) when I < N -> 
    if 
    I rem 2 == 0 -> io:format("~p~n",[I]), printEven(I+1,N); 
    I rem 2 == 1 -> printEven(I+1,N) 
    end; 
printEven(I,N) -> 
    io:format("Done"). 

mi piacerebbe molto avere l'ultimo caso appena esce automaticamente e non è necessario stampare qualsiasi cosa nella funzione. Ho provato a rimuoverlo, ma poi si verifica un errore da quando la ricorsione è terminata, viene generato un errore.

Come posso fare questo? C'è qualcosa come una parola chiave 'pass' o 'yield' in erlang?

+0

Umm, questo codice non può essere compilato - la prima clausola dovrebbe terminare con un punto e virgola non a punto. Lo stai eseguendo nella shell? Se lo sei, stamperà sempre ciò che restituisce e restituisce sempre qualcosa. Se non lo si esegue nella shell, basta rilasciare il formato io: ... –

risposta

11

OK, in primo luogo definire la funzione:

printEven(I,N) when I >= N -> ok; 
printEven(I,N)    -> 
    if 
    I rem 2 == 0 -> io:format("~p~n",[I]), printEven(I+1,N); 
    I rem 2 == 1 -> printEven(I+1,N) 
    end. 

Erlang è un linguaggio di programmazione funzionale e (per definizione) le funzioni di 'avere' un valore in modo che si sta per ottenere il 'qualcosa' indietro. Per convenzione, la cosa che si ottiene dopo aver completato una funzione che si sta utilizzando per gli effetti collaterali è atom ok, è il migliore da usare qui.

È possibile "silenziare" il valore restituito se lo si desidera. Tu fai che quando si richiama la funzione pattern matching al 'non interessa' variabile (che è di sottolineatura):

_ = printEven(3,9), 

o chiamando la funzione senza un pattern match:

printEven(3,9), 

Tuttavia, si sta molto meglio di controllare sempre i valori di ritorno da pattern matching quando si richiama una funzione:

ok = printEven(3,9), 

Questo è aa davvero buona abitudine di entrare in quanto si prevede di utilizzare un sacco di lib funzioni nee che restituiscono i codici di errore, come si può vedere dalle loro specifiche:

@spec funky(X) -> [ok | {error, bad_op} | {error, wig_out}] 

Se funky ha effetti collaterali che si vogliono sapere non è riuscita ora invocando con un pattern match quindi si arresterà qui e ora se funky fallisce:

ok = funky(99), 

Se corrispondono a '_' o ignorare il valore di ritorno andrà in crash 268 linee più tardi, quando il vostro mojo aspetta funky di aver fatto il suo thang, e poi è molto più difficile da trovare.

Questa è la felice programmazione del percorso che è la cosa fatta in Erlang. "Let it crash" è il motto. Se sei nuovo di Erlang lo troverai molto sconcertante, come camminare nudi. Non ti preoccupare di abbracciarlo, è una buona cosa. Porta a un sacco di codice "non scritto".

(Si dovrebbe anche prendere l'abitudine di mettere la clausola che termina la ricorsione come la clausola superiore come indicato qui - rende la lettura del codice sooo molto più facile quando si dispone di una funzione multi-clausola.)

+0

In realtà questo codice non è abbastanza carino, la seconda clausola dovrebbe essere scritta come: printEven (I, N) -> _ = se I rem 2 == 0 -> io: format ("~ p ~ n", [IO]); I rem 2 == 1 -> ok% stampa nulla fine, printEven (I + 1, N); Ricorda che la clausola if restituisce un valore - probabilmente non lo abbineresti in questo caso ma ho bloccato la partita per ricordarti che lo fa :) –

+0

Non solo puoi rendere le cose più belle evitando di dover scrivere la funzione ricorsiva chiama due volte, puoi rendere le cose più belle evitando di scrivere 'I rem 2' due volte con una dichiarazione di caso. Vedi la mia risposta. – 7stud

1

Credo che la parola chiave è "ok"

4

solo restituire un atomo.

printEven (I, N) -> done.

dovrebbe farlo.

+0

Non voglio che un atomo stampi, solo i numeri nel testo. – samoz

+0

un atomo non verrà stampato. fermerà il ciclo. –

+0

Dovrei chiarire, dovresti notare che il valore di ritorno di printEven non viene mai usato, quindi puoi far sì che restituisca tutto ciò che non include una chiamata ricorsiva. –

2

È anche possibile combinare il test per anche nella clausola di guardia. Preferisco anche il trucco atom fatto - mostra nel codice che è la clausola di funzione che fermerà la "ricorsione".

printEven(I, N) when I<N, I rem 2 == 0 -> 
    io:format("~p is even~n", [I]), 
    printEven(I+1, N); 
printEven(I,N) when I<N -> 
    printEven(I+1, N); 
printEven(I,N) -> 
    done. 
+0

C'è un modo per uscire silenziosamente? Senza un atomo? – samoz

+2

No - tutte le funzioni restituiscono un valore. Non stai testando il valore della funzione, quindi non sono sicuro del motivo per cui è importante per te? –

0
printEven(Start, Stop) when Start =< Stop -> 
    case Start rem 2 of 
     0 -> io:format("~p~n", [Start]); %returns ok 
     _ -> do_nothing 
    end, 
    printEven(Start+1, Stop); 
printEven(Start, Stop) when Start > Stop -> 
    ok. 

il valore della dichiarazione caso è o ok o do_nothing, ma la dichiarazione caso non è l'ultima espressione, quindi il suo valore non sarà il valore di ritorno per la prima clausola della funzione, e perché il valore dell'espressione case non è associata a una variabile, il valore viene semplicemente scartato.

L'ultima espressione nella prima clausola funzione è in realtà printEven(Start+1, Stop), e che chiamata di funzione finiranno ritorno ok volta ricorsività raggiunge la fine della sequenza ed esegue printEven(Start, Stop) when Start > Stop -> ok;

printEven(1, 3) => ? 
        | 
        V 
      printEven(2, 3) => ? 
           | --side effect: output 2 
           V 
         printEven(3, 3) => ? 
              | 
              V 
             printEven(4, 3) => ok 

compilazione del valore restituito per ogni chiamata di funzione in alto nella catena dà:

printEven(1, 3) => ok 
        ^
        | 
       printEven(2, 3) => ok 
           ^
           | 
         printEven(3, 3) => ok 
              ^
              | 
             printEven(4, 3) => ok 
-1

Questo lo farebbe:

printEven(I,N) -> ok. 
Problemi correlati