A sintaxe duplicada para definir funções nomeadas é uma decisão de design de linguagem ruim?

9

Estou modelando uma linguagem de programação por diversão, e a sintaxe é fortemente influenciada pelas definições de função do Scala - especificamente.

Eu encontrei um problema de design porque minha linguagem não diferencia entre funções definidas por meio da defsintaxe (métodos de classe) e funções anônimas atribuídas a valores (criados usando =>) - remove as diferenças de implementação e comportamento .

O resultado é que as duas definições a seguir significam a mesma coisa:

def square(x: Int) = x*x

val square = (x: Int) => x*x

Não há motivo para o último formulário (atribuição imediata de função anônima) ser usado em qualquer situação normal - é simplesmente possível usá-lo em vez do defformulário.

Ter essa sintaxe duplicada para definir funções nomeadas prejudicaria a ortogonalidade da linguagem ou algum outro aspecto do design?

Prefiro esta solução porque permite definições curtas e intuitivas de métodos e funções nomeadas (via def) e definições breves de funções anônimas (usando =>).

Editar: Scala faz diferenciar entre os dois - anónimo funções não são os mesmos como definidos com métodos defem Scala. As diferenças são relativamente sutis - veja as postagens que eu vinculei antes.

jcora
fonte
However, assigning existing functionsparece estar faltando o final da frase
Izkata
11
Você pode definir funções recursivas usando sua valnotação?
Giorgio
2
Eu verifiquei que isso também é possível em Scala. No SML, não é e você precisa usar funpara definir uma função recursiva.
Giorgio
3
A segunda forma não é realmente uma estrutura sintática especial, do jeito que defé. É apenas um efeito colateral do fato de que uma função anônima, digamos, (x : Int) => x + 1é um objeto, e os objetos podem ser atribuídos a valores com val f = .... Os projetistas da linguagem teria que sair de seu caminho para não permitir a sintaxe. Não é exatamente o mesmo que se esforçar explicitamente para oferecer suporte a duas sintaxes diferentes que fazem (aproximadamente) a mesma coisa.
KChaloux
3
A principal vantagem de fazer algo mais do que uma maneira em uma língua é que é uma ótima maneira de iniciar debates improdutivos religiosas que desviam dos problemas reais (pensando C ++ aqui) .......
mattnz

Respostas:

3

Eu acho que ter duas construções que significam a mesma coisa, mas com aparência diferente, deve ser mantido em um nível absolutamente mínimo em um idioma. Qualquer duplicação aumenta a dificuldade de ler (e, portanto, escrever / modificar o código) no seu idioma. A eliminação de toda duplicação é inevitável em um idioma que pode criar construções arbitrárias (por exemplo, a equivalência de iteração versus recursão).

Então, neste caso, acho que poderia ser melhor projetado aqui. Uma maneira única de definir funções faz mais sentido para mim. Nesse caso, parece que as duas declarações de escala que você tem realmente têm implicações ligeiramente diferentes, o que novamente provavelmente não é um bom design (provavelmente é melhor ter algo claro que indique quais são as diferenças, como uma palavra-chave).

De fato, você pode aplicar esse princípio não apenas às funções nomeadas, mas a qualquer função. Por que há alguma diferença na definição de funções nomeadas e funções anônimas? Em Lima , as funções são sempre definidas como este: fn[<arguments>: <statements>]. Se você quer que ele seja "chamado", você pode atribuí-lo a uma variável: var x = fn[<arguments: <statements>]e se você quiser passá-lo para outra função anonimamente: function[fn[<arguments: <statements>]]. Se você quiser que seja içado, faça-o constante const var x = fn[<arguments: <statements>]. A forma única torna óbvio que eles significam a mesma coisa.

BT
fonte
Isso é bastante interessante que constcausa içamento, mas faz todo o sentido. No JS function myFunc, o içamento causa, mas var myFunc =não o faz, o que talvez seja um pouco menos intuitivo, porque eles se comportam da mesma maneira.
MPEN
11
@pen Sim, na verdade, o javascript essencialmente faz a mesma coisa. de fato, a function fnName()...forma cria uma constante, que é o que torna a elevação uma coisa válida a ver com ela. Javascript torna as coisas bastante confusas quando você usa o formulário, var fn = function anotherFnName()...pois isso faz com que o nome anotherFnName não seja içado, mesmo que seja claramente constante.
BT
2

O que você postou é scala válido e funciona bem.

Dado que a duplicação não causou problemas com o scala (que eu saiba), vou dizer que também não será um problema para o seu idioma.

Daenyth
fonte
11
É válido no Scala, geralmente funciona da mesma forma, mas não significa a mesma coisa - e se você fizer exemplos mais complexos (o polimorfismo de tipo não está disponível para funções anônimas, por exemplo) - as diferenças se tornarão mais aparentes.
Jcora # 21/14
2

Eu encontrei uma diferença fundamental entre lambdas e defmétodos no Scala - que ainda não tenho certeza se quero implementar. Eu tenho que fazer uma pesquisa mais aprofundada sobre isso e depois relatarei minha decisão.

Essencialmente, apenas métodos podem return- e quando a palavra-chave é usada em um lambda, ela realmente retorna do método abrangente.

Como eu disse, não tenho certeza se quero isso. Mas isso poderia ser justificativa suficiente para esta sintaxe. Ou talvez muito perigoso, porque diferenças sutis podem causar danos inesperadamente.

Detalhes

jcora
fonte