Perché non annotare i parametri della funzione?

27

Per rispondere a questa domanda, supponiamo che il costo dell'ambiguità nella mente di un programmatore sia molto più costoso di alcune sequenze di tasti in più.

Detto questo, perché dovrei permettere ai miei compagni di squadra di fare a meno di non che annotano i loro parametri di funzione? Prendi il seguente codice come esempio di ciò che potrebbe essere una parte di codice molto più complessa:

let foo x y = x + y

Ora, un rapido esame del tooltip ti mostrerà che F # ha determinato che intendevi per xey essere int. Se è quello che intendevi, allora va tutto bene. Ma I non so se è quello che intendevi. E se avessi creato questo codice per concatenare due stringhe insieme? O se pensi che probabilmente hai intenzione di aggiungere i doppi? O se non volessi dover passare il mouse sopra ogni singolo parametro di funzione per determinarne il tipo?

Ora prendi questo come esempio:

let foo x y = "result: " + x + y

F # ora presume che tu abbia probabilmente intenzione di concatenare le stringhe, quindi xey sono definite come stringhe. Tuttavia, come il povero schmuck che sta mantenendo il tuo codice, potrei guardarlo e chiedermi se forse avevi intenzione di aggiungere x e y (ints) insieme e quindi aggiungere il risultato a una stringa per scopi di interfaccia utente.

Certamente per esempi così semplici si potrebbe lasciarlo andare, ma perché non applicare una politica di annotazione esplicita del tipo?

let foo (x:string) (y:string) = "result: " + x + y

Che danno c'è nell'essere inequivocabili? Certo, un programmatore potrebbe scegliere i tipi sbagliati per quello che stanno cercando di fare, ma almeno so che l'avevano previsto, che non era solo una svista.

Questa è una domanda seria ... Sono ancora molto nuovo su F # e sto aprendo la strada alla mia azienda. Gli standard che adotterò saranno probabilmente la base per tutta la futura codifica F #, incorporata nell'infinita copia-incolla che sono sicuro permeerà la cultura per gli anni a venire.

Quindi ... c'è qualcosa di speciale nell'inferenza di tipo di F # che la rende una caratteristica preziosa su cui aggrapparsi, annotando solo quando necessario? Oppure gli esperti F # -er hanno l'abitudine di annotare i loro parametri per applicazioni non banali?

    
posta JDB 16.12.2013 - 23:42
fonte

3 risposte

30

Non uso F #, ma in Haskell è considerata una buona forma per annotare (almeno) definizioni di alto livello e talvolta definizioni locali, anche se la lingua ha inferenza di tipo pervasivo. Questo è per alcuni motivi:

  • Lettura
    Quando vuoi sapere come usare una funzione, è incredibilmente utile avere la firma del tipo disponibile. Puoi semplicemente leggerlo, piuttosto che cercare di dedurlo da solo o affidarti a strumenti per farlo per te.

  • refactoring
    Quando vuoi modificare una funzione, avere una firma esplicita ti dà la certezza che le tue trasformazioni mantengono l'intento del codice originale. In una lingua con deduzione di tipo, potresti scoprire che il codice altamente polimorfico eseguirà il controllo tipografico ma non eseguirà ciò che hai inteso. La firma del tipo è una "barriera" che concretizza le informazioni di tipo su un'interfaccia.

  • Performance
    In Haskell, il tipo inferito di una funzione può essere sovraccaricato (a titolo di typeclass), il che può implicare una distribuzione in runtime. Per i tipi numerici, il tipo predefinito è un numero intero di precisione arbitraria. Se non hai bisogno della completa generalità di queste funzionalità, puoi migliorare le prestazioni specializzando la funzione in base al tipo specifico di cui hai bisogno.

Per le definizioni locali, le variabili let -bound e i parametri formali per lambdas, trovo che le firme di tipo di solito costano di più nel codice rispetto al valore che aggiungerebbero. Pertanto, nella revisione del codice, ti suggerisco di insistere sulle firme per le definizioni di massimo livello e di chiedere semplicemente annotazioni giudiziose altrove.

    
risposta data 17.12.2013 - 00:20
fonte
1

Jon ha dato una ragionevole risposta che non ripeterò qui. Ti mostrerò comunque un'opzione che potrebbe soddisfare le tue esigenze e nel processo vedrai un diverso tipo di risposta diverso da un sì / no.

Ultimamente ho lavorato con l'analisi usando i combinatori di parser. Se conosci l'analisi, sai che in genere usi un lexer nella prima fase e un parser nella seconda fase. Il lexer converte il testo in token e il parser converte i token in un AST. Ora che F # è un linguaggio funzionale e i combinatori progettati per essere combinati, i combinatori di parser sono progettati per utilizzare le stesse funzioni sia nel lexer che nel parser, ma se si imposta il tipo per le funzioni del combinatore di parser è possibile utilizzarli solo per lex o per analizzare e non entrambi.

Ad esempio:

/// Parser that requires a specific item.

// a (tok : 'a) : ('a list -> 'a * 'a list)                     // generic
// a (tok : string) : (string list -> string * string list)     // string
// a (tok : token)  : (token list  -> token  * token list)      // token

o

/// Parses iterated left-associated binary operator.


// leftbin (prs : 'a -> 'b * 'c) (sep : 'c -> 'd * 'a) (cons : 'd -> 'b -> 'b -> 'b) (err : string) : ('a -> 'b * 'c)                                                                                    // generic
// leftbin (prs : string list -> string * string list) (sep : string list -> string * string list) (cons : string -> string -> string -> string) (err : string) : (string list -> string * string list)  // string
// leftbin (prs : token list  -> token  * token list)  (sep : token list  -> token  * token list)  (cons : token  -> token  -> token  -> token)  (err : string) : (token list  -> token  * token list)   // token

Poiché il codice è copyright, non lo includerò qui, ma è disponibile all'indirizzo Github . Non copiarlo qui.

Affinché le funzioni funzionino, devono essere lasciati con i parametri generici, ma includo commenti che mostrano i tipi dedotti a seconda delle funzioni utilizzate. Ciò semplifica la comprensione della funzione per la manutenzione lasciando la funzione generica per l'uso.

    
risposta data 17.12.2013 - 00:58
fonte
-8

Il numero di bug è direttamente proporzionale al numero di caratteri in un programma!

Di solito viene indicato come il numero di bug che è proporzionale alle linee di codice. Ma avere meno linee con la stessa quantità di codice dà la stessa quantità di errori.

Quindi, mentre è bello essere espliciti, qualsiasi altro parametro digitato può portare a bug.

    
risposta data 17.12.2013 - 02:37
fonte

Leggi altre domande sui tag