L'aggiunta di typespecs sarà drammaticamente migliorare la precisione di Dialyzer.
Poiché Erlang è un linguaggio dinamico, Dialyzer deve impostare un'interpretazione piuttosto ampia dei tipi, a meno che non gli suggerisca di limitare la digitazione di "successo". Pensalo come se dia a Dialyzer un filtro con il quale può trasformare una serie di possibili successi in un sottoinsieme di tipi espliciti che dovrebbe funzionare mai.
Questo non è lo stesso di Haskell, dove l'ipotesi di default è fallita e tutto il codice deve essere scritto con successo digitando per essere compilato a tutti - Dialyzer deve default per assumere successo a meno che non sappia per certo che un tipo sta andando fallire.
Typespecs sono la parte principale di questo, ma Dialyzer controlla anche le guardie, quindi una funzione come
increment(A) -> A + 1.
non è lo stesso di
increment(A) when A > 100 -> A + 1.
Anche se entrambi possono essere tipizzato come
-spec increment(integer()) -> integer().
Per la maggior parte del tempo ci si preoccupa solo di valori interi pari a integer()
, pos_integer()
, neg_integer()
o non_neg_integer()
, ma a volte è necessario un intervallo arbitrario limitato su un lato e la lingua del tipo non ha modo di rappresentarlo al momento (sebbene personalmente mi piacerebbe vedere una dichiarazione di 100..infinity
come previsto).
Il illimitata gamma di when A > 100
richiede una guardia, ma una gamma limitata come when A > 100 and A < 201
potrebbe essere rappresentato nel solo typespec:
-spec increment(101..200) -> pos_integer().
increment(A) -> %stuff.
guardie sono veloce con l'eccezione di chiamare length/1
(che si dovrebbe probabilmente non è mai veramente necessario in una guardia), quindi non preoccuparti del sovraccarico delle prestazioni finché non lo sai e puoi dimostrare che hai un problema di prestazioni che proviene dalle guardie. L'utilizzo delle protezioni e per il tipo di Dialyzer è estremamente utile. È anche molto utile come documentazione per te stesso e specialmente se usi edoc, dato che il typespec verrà mostrato lì, rendendo le API meno misteriose e facili da usare a colpo d'occhio.
C'è una letteratura interessante sull'uso di Dialyzer in basi di codice esistenti. Un'esperienza ben documentata è qui: Gradual Typing of Erlang Programs: A Wrangler Experience. (Sfortunatamente alcuni degli altri link che ho imparato molto in precedenza sono scomparsi o sono stati spostati. (!.!Un'attenta lettura della carta Wrangler, sfiorando lo User's Guide e man page, giocando con Dialyzer, e qualche precedente esperienza in un sistema di tipi come quello di Haskell, più che prepararsi a ottenere molto chilometraggio da Dialyzer, però.)
[Su una nota a margine, ho parlato con alcune persone prima di specificare le funzioni "pure" che potrebbero essere garantite come fortemente digitate con una notazione o usando una sintassi diversa definizione (forse Prolog :-
invece di Erlang ->
. .. o qualcosa del genere), ma anche se sarebbe bello, ed è molto possibile anche adesso concentrare gli effetti collaterali in una piccola parte del programma e passare tutti i risultati indietro in una tupla di {Results, SideEffectsTODO}
, questo non è semplicemente un bisogno urgente ed Erlang funziona maledettamente bene così com'è. Ma Dialyzer è davvero molto utile per mostrarti dove hai perso la cognizione di te!]
Grazie per la risposta dettagliata :) Prima di chiedere questo, ho aggiunto un po 'di specifiche qua e là al codice base, non aiutare una cosa, suppongo di aver aggiunto troppo meno o di aver aggiunto la parte banale (la parte che il dializzatore ha intuito accuratamente). Mi manca ancora il sistema di tipi di Haskell :( –
@NotanID Mi manca anche questo! Ecco perché mi piacerebbe avere un modo per dichiarare le funzioni rigide/pure costruite dal compilatore.In generale i benefici nella produzione dell'approccio di Erlang sono piuttosto travolgenti (e tu non otterrà errori di compilazione casuali perché qualcuno ha manipolato misteri proibiti in Cabal questa settimana), ma sarebbe bello avere un metodo forzato di definizioni pure o un metodo formale di operazioni di monadificazione con un burrito con effetti collaterali differiti come '{Valori , TODOs} 'che Dialyzer o il compilatore sapevano lamentarsi se avesse un odore divertente. (Hmmm ... il sistema di tipo" puzzolente burrito ".) – zxq9
Detto questo, Dialyzer è anche bravo nel determinare i tipi da solo. d suggerisco di aggiungere solo specifiche specifiche del tipo usando lo strumento 'typer' per identificare i luoghi in cui Dialyzer non ha individuato i tipi Personalmente, penso che l'eccessiva speciazione dei tipi renda il codice più illeggibile –