Para responder a essa pergunta, vamos supor que o custo da ambiguidade na mente de um programador seja muito mais caro do que algumas teclas extras.
Dado isso, por que eu permitiria que meus colegas de equipe não anotassem seus parâmetros de função? Tome o código a seguir como um exemplo do que poderia ser um pedaço de código muito mais complexo:
let foo x y = x + y
Agora, um rápido exame da dica mostrará que o F # determinou que você pretendia que x e y fossem ints. Se é isso que você pretendia, tudo está bem. Mas eu não sei se é isso que você pretendia. E se você tivesse criado esse código para concatenar duas strings juntas? Ou então, se eu acho que você provavelmente pretendia adicionar duplas? Ou, se eu simplesmente não quiser passar o mouse sobre cada parâmetro de função para determinar seu tipo?
Agora tome isso como um exemplo:
let foo x y = "result: " + x + y
O F # agora supõe que você provavelmente pretendeu concatenar cadeias de caracteres, então x e y são definidos como cadeias de caracteres. No entanto, como o pobre coitado que está mantendo seu código, eu posso olhar para isso e me perguntar se talvez você pretendesse adicionar x e y (ints) juntos e depois anexar o resultado a uma string para fins de interface do usuário.
Certamente, para exemplos tão simples, é possível deixar para lá, mas por que não impor uma política de anotação explícita de tipo?
let foo (x:string) (y:string) = "result: " + x + y
Que mal há em ser inequívoco? Claro, um programador poderia escolher os tipos errados para o que eles estão tentando fazer, mas pelo menos eu sei que eles pretendiam, que não era apenas uma supervisão.
Essa é uma pergunta séria ... Ainda sou muito novo no F # e estou abrindo caminho para a minha empresa. Os padrões que eu adotar provavelmente serão a base para toda a futura codificação de F #, incorporada na infinita cópia de pasta que tenho certeza de que permeará a cultura nos próximos anos.
Então ... existe algo especial na inferência de tipo do F # que o torna um recurso valioso para se agarrar, anotando apenas quando necessário? Ou os especialistas em F # têm o hábito de anotar seus parâmetros para aplicativos não triviais?
fonte
Respostas:
Eu não uso o F #, mas no Haskell é considerado uma boa forma anotar (pelo menos) definições de nível superior e, às vezes, definições locais, mesmo que o idioma tenha inferência generalizada de tipo. Isso ocorre por alguns motivos:
Leitura
Quando você quer saber como usar uma função, é incrivelmente útil ter a assinatura de tipo disponível. Você pode simplesmente lê-lo, em vez de tentar inferir você mesmo ou confiar em ferramentas para fazer isso por você.
Refatoração
Quando você deseja alterar uma função, ter uma assinatura explícita garante a você que suas transformações preservam a intenção do código original. Em uma linguagem deduzida por tipo, você pode achar que o código altamente polimórfico verificará tipicamente, mas não fará o que você pretendia. A assinatura de tipo é uma “barreira” que concretiza informações de tipo em uma interface.
Desempenho
No Haskell, o tipo inferido de uma função pode estar sobrecarregado (por meio de classes de tipos), o que pode implicar um despacho em tempo de execução. Para tipos numéricos, o tipo padrão é um número inteiro de precisão arbitrária. Se você não precisar da generalidade completa desses recursos, poderá melhorar o desempenho, especializando a função para o tipo específico de que precisa.
Para definições locais,
let
variáveis de saída e parâmetros formais para lambdas, acho que as assinaturas de tipo geralmente custam mais em código do que o valor que elas adicionariam. Portanto, na revisão de código, sugiro que você insista em assinaturas para definições de nível superior e apenas peça anotações criteriosas em outros lugares.fonte
.mli
arquivo interface ( ) (se você escrever uma que é altamente recomendável. As anotações de tipo tendem a ser omitidas das definições porque seriam redundantes com a interface..fsi
arquivos de assinatura do F # ( ), com uma ressalva: o F # não usa arquivos de assinatura para inferência de tipo; portanto, se algo na implementação for ambíguo, você ainda precisará anotá-lo novamente. books.google.ca/…Jon deu uma resposta razoável que não vou repetir aqui. No entanto, mostrarei uma opção que pode satisfazer suas necessidades e, no processo, você verá um tipo de resposta diferente de sim / não.
Ultimamente, tenho trabalhado com a análise usando combinadores de analisadores. Se você conhece a análise, sabe que normalmente usa um lexer na primeira fase e um analisador na segunda fase. O lexer converte texto em tokens e o analisador converte tokens em um AST. Agora, com o F # sendo uma linguagem funcional e combinadores projetados para serem combinados, os combinadores de analisadores são projetados para usar as mesmas funções no lexer e no analisador; no entanto, se você definir o tipo para as funções do combinador de analisador, você só poderá usá-los para lex ou analisar e não ambos.
Por exemplo:
ou
Como o código é protegido por direitos autorais, não o incluirei aqui, mas está disponível no Github . Não copie aqui.
Para que as funções funcionem, elas devem ser deixadas com os parâmetros genéricos, mas eu incluo comentários que mostram os tipos inferidos, dependendo do uso das funções. Isso facilita o entendimento da função para manutenção, deixando a função genérica para uso.
fonte
O número de bugs é diretamente proporcional ao número de caracteres em um programa!
Isso geralmente é declarado como o número de erros proporcional às linhas de código. Mas ter menos linhas com a mesma quantidade de código gera a mesma quantidade de bugs.
Portanto, embora seja bom ser explícito, qualquer parâmetro extra digitado pode levar a erros.
fonte