La sintassi duplicata per la definizione di funzioni con nome è una cattiva decisione di progettazione del linguaggio?


9

Sto modellando un linguaggio di programmazione per divertimento e la sintassi è fortemente influenzata da Scala, in particolare dalle definizioni delle funzioni.

Ho riscontrato un problema di progettazione perché il mio linguaggio non distingue tra funzioni definite tramite la defsintassi (metodi di classe) e funzioni anonime assegnate ai valori (creati usando =>) - rimuove le differenze sia nell'implementazione che nel comportamento .

Il risultato è che le seguenti due definizioni significano la stessa cosa:

def square(x: Int) = x*x

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

Non vi è alcun motivo per utilizzare quest'ultimo modulo (assegnazione immediata della funzione anonima) in qualsiasi situazione normale: è semplicemente possibile utilizzarlo al posto del defmodulo.

Avere una sintassi così duplicata per definire le funzioni con nome danneggerebbe l'ortogonalità del linguaggio o qualche altro aspetto del design?

Preferisco questa soluzione perché consente definizioni brevi e intuitive di metodi e funzioni denominate (via def) e definizioni brevi di funzioni anonime (utilizzo =>).

Edit: Scala fa distinguere tra i due - anonimo funzioni non sono le stesse di metodi definiti con defa Scala. Le differenze sono tuttavia relativamente sottili: vedi i post che ho collegato prima.


However, assigning existing functionssembra mancare la fine della frase
Izkata,

1
Puoi definire le funzioni ricorsive usando la tua valnotazione?
Giorgio,

2
Ho verificato che ciò è possibile anche in Scala. In SML non lo è e devi usarlo funper definire una funzione ricorsiva.
Giorgio,

3
La seconda forma non è in realtà una struttura sintattica speciale, il modo defè. È solo un effetto collaterale del fatto che una funzione anonima, ad esempio, (x : Int) => x + 1è un oggetto e gli oggetti possono essere assegnati a valori con val f = .... I progettisti linguistici avrebbero dovuto fare di tutto per impedire la sintassi. Non è esattamente lo stesso di impegnarsi esplicitamente per supportare due diverse sintassi che fanno (approssimativamente) la stessa cosa.
KChaloux,

3
Il principale vantaggio di fare qualcosa in più di un modo in una lingua è che è un ottimo modo per avviare dibattiti religiosi improduttivi che distraggono dai problemi reali (Pensare al C ++ qui) .......
mattnz

Risposte:


3

Penso che avere due costrutti che significano la stessa cosa ma sembrano diversi dovrebbe essere ridotto al minimo in una lingua. Qualsiasi duplicazione aumenta la difficoltà a leggere (e quindi scrivere / modificare il codice) nella tua lingua. L'eliminazione di ogni duplicazione è inevitabile in un linguaggio che può creare costrutti arbitrari (ad esempio, l'equivalenza dell'iterazione rispetto alla ricorsione).

Quindi, in questo caso, penso che potrebbe essere progettato meglio qui. Un singolo modo per definire le funzioni ha più senso per me. In questo caso, sembra che le due dichiarazioni scala che hai effettivamente abbiano implicazioni leggermente diverse, che di nuovo probabilmente non è un buon design (probabilmente è meglio avere qualcosa di chiaro che indichi quali differenze, come una parola chiave).

In effetti, puoi applicare questo principio non solo alle funzioni nominate, ma a qualsiasi funzione. Perché ci sono differenze nella definizione di funzioni nominate e funzioni anonime? In Lima , le funzioni sono sempre definite in questo modo: fn[<arguments>: <statements>]. Se si vuole che sia "nominato" è possibile assegnare ad una variabile: var x = fn[<arguments: <statements>]e se si desidera passare a un'altra funzione anonima: function[fn[<arguments: <statements>]]. Se lo vuoi sollevato, rendilo costante const var x = fn[<arguments: <statements>]. La singola forma rende ovvio che significano la stessa cosa.


È abbastanza interessante che constprovoca il sollevamento, ma ha perfettamente senso. In JS function myFuncprovoca il sollevamento, ma var myFunc =non lo è, il che è forse un po 'meno intuitivo perché si comportano più o meno allo stesso modo altrimenti.
aprono il

1
@mpen Sì, in realtà javascript essenzialmente fa la stessa cosa. la function fnName()...forma infatti crea una costante, che è ciò che rende il sollevamento una cosa valida da fare con essa. Javascript rende le cose piuttosto confuse quando si utilizza il modulo var fn = function anotherFnName()...poiché ciò anotherFnName non solleva il nome , anche se è chiaramente costante.
BT,

2

Quello che hai pubblicato è valido scala e funziona bene.

Dato che il raddoppio non ha causato problemi con Scala (per quanto ne sappia), sto per dire che non sarà nemmeno un problema per la tua lingua.


1
È valido in Scala, per lo più funziona allo stesso modo, ma non significa la stessa cosa - e se faresti esempi più complessi (il polimorfismo del tipo non è disponibile per funzioni anonime, ad esempio) - le differenze diventerebbero più evidenti.
jcora,

2

Ho trovato una differenza fondamentale tra lambda e defmetodi in Scala - che non sono ancora sicuro di voler implementare. Devo fare ulteriori ricerche al riguardo e poi riferirò sulla mia decisione.

In sostanza, solo i metodi possono return- e quando la parola chiave viene utilizzata da un lambda, in realtà ritorna dal metodo globale.

Come ho già detto, non sono sicuro di volerlo. Ma potrebbe essere una giustificazione sufficiente per questa sintassi. O forse troppo pericoloso perché differenze sottili possono inaspettatamente causare danni.

Dettagli

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.