A idéia é inspirada no fato de que operadores como +, -,% etc. podem ser vistos como funções com um ou dois argumentos passados e sem efeitos colaterais. Supondo que eu, ou outra pessoa, escreva uma linguagem que impeça a passagem de mais de dois argumentos e também funcione apenas via valor de retorno:
a) essa linguagem levaria a um código mais fácil de entender?
b) o fluxo do código seria mais claro? (forçado a mais etapas, com potencialmente menos interações "ocultas"
c) as restrições tornariam o idioma excessivamente volumoso para programas mais complexos.
d) (bônus) quaisquer outros comentários sobre prós / contras
Nota:
Duas decisões ainda precisam ser tomadas - a primeira é permitir a entrada do usuário fora de main () ou equivalente, e também qual será a regra em relação ao que acontece ao passar matrizes / estruturas. Por exemplo, se alguém quiser que uma única função adicione vários valores, ele poderá contornar a limitação agrupando-a em uma matriz. Isso pode ser interrompido não permitindo que uma matriz ou estrutura interaja consigo mesma, o que ainda permitiria, por exemplo, dividir cada número por uma quantidade diferente, dependendo da posição.
result = f(a)(b)…(z)
. É o caso da família de idiomas ML, como Haskell, mas também conceitualmente em outros idiomas, como Lisp, JavaScript ou Perl.Respostas:
Robert C. Martin em seu livro "Clean Code" recomenda fortemente o uso de funções com 0, 1 ou 2 parâmetros no máximo; portanto, pelo menos há um autor de livro experiente que acha que o código se torna mais limpo usando esse estilo (no entanto, ele é certamente não a autoridade ultimativa aqui, e suas opiniões são discutíveis).
Onde Bob Martin está IMHO correto é: funções com 3 ou mais parâmetros geralmente são indicadores de um cheiro de código. Em muitos casos, os parâmetros podem ser agrupados para formar um tipo de dados combinado; em outros casos, pode ser um indicador para a função simplesmente fazendo muito.
No entanto, não acho que seria uma boa ideia inventar um novo idioma para isso:
se você realmente deseja impor essa regra em todo o seu código, precisa apenas de uma ferramenta de análise de código para um idioma existente, não há necessidade de inventar um idioma completamente novo para isso (por exemplo, para C #, algo como 'fxcop' provavelmente poderia ser utilizado )
às vezes, combinar parâmetros com um novo tipo simplesmente não parece incomodar, ou isso se tornaria uma combinação artificial pura. Veja, por exemplo, este
File.Open
método na estrutura .Net. São necessários quatro parâmetros, e tenho certeza de que os projetistas dessa API fizeram isso intencionalmente, porque acharam que seria a maneira mais prática de fornecer os parâmetros diferentes para a função.Às vezes, existem cenários do mundo real em que mais de 2 parâmetros simplificam as coisas por motivos técnicos (por exemplo, quando você precisa de um mapeamento 1: 1 para uma API existente em que está vinculado ao uso de tipos de dados simples e não pode combinar diferentes parâmetros em um objeto personalizado)
fonte
Existem muitos idiomas que já funcionam dessa maneira, por exemplo, Haskell. Em Haskell, toda função usa exatamente um argumento e retorna exatamente um valor.
Sempre é possível substituir uma função que aceita n argumentos por uma função que aceita n-1 e retorna uma função que aceita o argumento final. Aplicando isso recursivamente, sempre é possível substituir uma função que recebe um número arbitrário de argumentos por uma função que recebe exatamente um argumento. E essa transformação pode ser realizada mecanicamente, por um algoritmo.
Isso se chama Frege-Schönfinkeling, Schönfinkeling, Schönfinkel-Currying ou Currying, em homenagem a Haskell Curry, que a pesquisou extensivamente na década de 1950, Moses Schönfinkel, que a descreveu em 1924, e Gottlob Frege, que a antecipou em 1893.
Em outras palavras, restringir o número de argumentos tem exatamente zero impacto.
fonte
f *(call_with: a,b,c,d,e)
Sobrecargacall_with :
para iniciar uma cadeia,,
estender a cadeia e,*
no LHS, invocarf
passando cada conteúdo da cadeia, um de cada vez. Um sistema de sobrecarga de operador suficientemente fraco apenas torna a sintaxe complicada, mas isso é culpa do sistema de sobrecarga de operador mais do que qualquer coisa.Passei algum tempo nessas últimas semanas tentando aprender a linguagem de computador. Em J, praticamente tudo é um operador, então você só recebe "mônadas" (funções que possuem apenas um argumento) e "díades" (funções com exatamente dois argumentos). Se você precisar de mais argumentos, precisará fornecê-los em uma matriz ou em "caixas".
J pode ser muito conciso, mas, como seu APL predecessor, também pode ser muito enigmático - mas isso é principalmente o resultado do objetivo do criador de imitar a sucessão matemática. É possível tornar um programa J mais legível usando nomes em vez de caracteres para criar operadores.
fonte
Uma linguagem baseada em como restringe o desenvolvedor depende da suposição de que o desenvolvedor da linguagem entende melhor as necessidades de cada programador do que o próprio programador. Há casos em que isso é realmente válido. Por exemplo, muitas restrições na programação multithread que requerem sincronização usando mutexes e semáforos são "boas" porque muitos programadores desconhecem completamente as complexidades subjacentes específicas à máquina que essas restrições ocultam. Da mesma forma, poucos desejam entender completamente as nuances dos algoritmos de coleta de lixo multithread; uma linguagem que simplesmente não permite que você quebre o algoritmo do GC é preferível a uma que força o programador a estar ciente de muitas nuances.
Você teria que apresentar um argumento válido para o motivo pelo qual, como desenvolvedor de linguagem, você entende que a passagem de argumentos é muito melhor do que os programadores que usam sua linguagem, que há valor em impedir que eles façam coisas que considere prejudiciais. Eu acho que seria um argumento difícil de argumentar.
Você também tem que saber que os programadores vão contornar suas limitações. Se eles precisarem de três ou mais argumentos, eles usarão técnicas como currying para transformá-los em chamadas com menos argumentos. No entanto, isso geralmente custa à legibilidade, em vez de melhorá-la.
A maioria das linguagens que conheço com esse tipo de regra são esolangs, linguagens projetadas para demonstrar que você pode realmente operar com um conjunto limitado de funcionalidades. Em particular, os esolangs em que cada caractere é um código de operação tendem a limitar o número de argumentos, simplesmente porque precisam manter a lista de códigos de operação curta.
fonte
Você precisará de duas coisas:
Vou adicionar um exemplo matemático para explicar a resposta escrita por Jörg W Mittag .
Considere a função gaussiana .
Uma função gaussiana tem dois parâmetros para sua forma, a saber, a média (posição central da curva) e a variância (relacionada à largura de pulso da curva). Além dos dois parâmetros, é preciso também fornecer o valor da variável livre
x
para avaliá-la.Na primeira etapa, projetaremos uma função gaussiana que aceita todos os três parâmetros, a média, a variância e a variável livre.
Na segunda etapa, criamos um tipo de dados composto que combina a média e a variação em uma coisa.
Na terceira etapa, criamos uma parametrização da função Gaussiana, criando um fechamento da função Gaussiana ligada ao tipo de dados composto que criamos na segunda etapa.
Por fim, avaliamos o fechamento criado na terceira etapa, passando o valor da variável livre
x
para ela.A estrutura é, portanto:
fonte
Em praticamente qualquer linguagem de programação, você pode passar algum tipo de lista, matriz, tupla, registro ou objeto como o único argumento. Seu único objetivo é armazenar outros itens em vez de passá-los para uma função individualmente. Alguns IDE Java ainda têm um recurso " Extrair objeto de parâmetro " para fazer exatamente isso. Internamente, o Java implementa números variáveis de argumentos criando e passando uma matriz.
Se você realmente deseja fazer o que está falando da forma mais pura, precisa analisar o cálculo lambda. É exatamente o que você descreve. Você pode pesquisar na web, mas a descrição que fazia sentido para mim estava em Tipos e Linguagens de Programação .
Veja as linguagens de programação Haskell e ML (ML é mais simples). Ambos são baseados no cálculo lambda e conceitualmente têm apenas um parâmetro por função (se você apertar um pouco).
O item 2 de Josh Bloch é: "Considere um construtor quando confrontado com muitos parâmetros de construtor". Você pode ver como isso fica detalhado , mas é uma delícia trabalhar com uma API que é escrita dessa maneira.
Algumas linguagens nomearam parâmetros, que é outra abordagem para facilitar a navegação de grandes assinaturas de métodos. Kotlin nomeou argumentos, por exemplo.
fonte