2011-12-14 14 views
5

Sto scrivendo un piccolo servizio di erlang e vorrei mettere dei vincoli sui miei tipi.Come utilizzare la funzionalità -spec in erlang

Ho trovato la funzionalità -spec e mi sembra che questo sia un modo per "bloccare" le firme delle funzioni su tipi specifici.

mio esempio potrebbe essere una funzione come:

fib(N) when N < 3 -> 
    1; 
fib(N) -> 
    fib(N-1) + fib(N-2). 

aggiungendo la riga

-spec fib_cps(pos_integer()) -> pos_integer(). 

dovrebbe assicurarsi che il metodo restituisce atleast il tipo corretto, ma questo non sembra essere il caso. .

per Se cambio la funzione di:

fib(N) when N < 3 -> 
    ok; 
fib(N) -> 
    not_ok. 

il codice è ancora compilato, funziona bene e anche.

Cosa sto fraintendendo?

+1

BTW, la tua specifica di tipo dovrebbe apparire come '-spec fib_cps (pos_integer()) -> pos_integer().' (Nota le parentesi vuote), altrimenti Dialyzer pensa che tu intenda l'atomo 'pos_integer'. – legoscia

risposta

11

Il compilatore ignora tali commenti. Ma puoi usare il dializzatore per fare analisi del codice statico. Questo strumento ti avviserà delle violazioni delle specifiche.

+0

Significa che per garantire il codice "stabile" è necessario eseguire lo strumento dializzatore ontop del compilatore? È così che vai in giro per l'intero problema di typechecking? –

+0

@MartinKristiansen Sì, se si desidera un codice di produzione stabile, è necessario eseguire dializzatore. Forse non tutte le build, ma periodicamente. Ad esempio, puoi integrarlo con il sistema di build giornaliero, se ne usi uno. – werewindle

1

Come werewindle dice in another answer, -spec viene utilizzato solo per l'analisi, non come parte della firma. Se si desidera verificare i tipi di input, è possibile includere controlli per il tipo nella guardia. Quindi, nel tuo esempio, si può fare:

fib(N) when is_integer(N), N > 0, N < 3 -> 
    1; 
fib(N) when is_integer(N), N >= 3 -> 
    fib(N-1) + fib(N-2). 

O, più idiomatico, dato che ci sono solo due casi di base legittimi:

fib(1) -> 1; 
fib(2) -> 1; 
fib(N) when is_integer(N), N >= 3 -> 
    fib(N-1) + fib(N-2). 

Questo ti impedisce di fare qualcosa di simile fib(bogus) o fib(0.5) o anche fib(-1). Se ci provi, fallirà con un badmatch in fase di runtime.

Nota: le uniche funzioni che è possibile utilizzare in un guard sono funzioni integrate consentite dal runtime. Molti di questi sono nel modulo erlang.

+0

Vedo, ma quello che mi piacerebbe davvero è una sorta di tipizzazione statica, come in ML. Significato che mi piacerebbe specificare un tipo A: = C | D. E quindi definire il metodo per avere il tipo forinstance (_ -> A). Conoscete le lingue con buoni meccanismi di concorrenza che sono in grado di fare quel genere di cose? –

+2

@MartinKristiansen: dializzatore è uno strumento erlang standard. Viene fornito con erlang e dovrebbe essere utilizzato in qualsiasi progetto di erlang. Sì, l'analisi statica non fa parte del compilatore, ma comunque puoi farlo ogni volta che vuoi. Immagina, se il preprocessore C fosse uno strumento separato dal compilatore. Sarebbe in qualche modo a disagio, ma ok. – werewindle

Problemi correlati