Scelta di una sintassi per espressioni che generano elenchi [chiuso]
Domanda
C # ha funzioni di generatore che hanno sintassi come:
IEnumerable<int> GetNats(int max)
{
for (int i=0; i < max; ++i)
yield return i;
}
Una caratteristica che mi interessa per il mio linguaggio di programmazione (una semplice programmazione orientata agli oggetti simile a Java, Scala, ActionScript e C #) sono espressioni di generatori. Questi sono essenzialmente zuccheri sintattici per le funzioni del generatore.
Il mio attuale candidato preferito è la seguente sintassi:
IEnumerable<int> nats =
witheach (i in range(0, 42))
yield i * 2;
L'espressione range (0, 42)
è una funzione del generatore integrata.
Quindi la mia domanda è quale sintassi preferiresti vedere per le espressioni del generatore, in un linguaggio di tipo C # / Java / Scala / ActionScript, e perché?
Alcuni fattori che possono influenzare le risposte sono che come Scala e ActionScript, i tipi nella mia lingua sono dichiarati dopo il tipo. Ad esempio:
var myVar : SomeType = initialValue;
Anche le funzioni anonime sono così:
var myFunc = function(int x) {
return x + 1;
}
A parte questo, la sintassi del resto del mio linguaggio assomiglia a Java o C #. La mia lingua ha un'istruzione foreach
che è molto simile a C #.
Soluzione
C'è anche l'approccio di Python - nessuna sintassi speciale per i generatori; la presenza di un "rendimento" l'affermazione è tutto ciò che serve. Qualsiasi affermazione che richiede un blocco potrebbe essere utilizzata, anche se mi aspetto di trovare solo i loop utilizzati nella pratica:
IEnumerable<int> nats =
for (i in range(0,42))
yield i*2
String phrase = "I want to buy some cheese.";
IEnumerable<int> substrs =
for (i in 0 .. phrase.length)
for (j in i .. phrase.length+1)
yield phrase[i..j]
Qui presumo che l'endpoint giusto non sia incluso in un intervallo.
Ad essere sincero, quando l'ho visto in Python, mi sono chiesto: "a quale costo?"
Altri suggerimenti
Scopri cosa fa F #. Puoi farlo
seq { seq-expr } // IEnumerable<T>, a.k.a. seq<T>
[ seq-expr ] // list<T>
[| seq-expr |] // array<T>
dove seq-expr è una forma che include la maggior parte dei costrutti del linguaggio insieme a 'yield'. Quindi ad es. puoi scrivere
seq {
for i in 0..9 do
for j in someColl do
if i <> j then
yield i*j
}
Il compilatore F # traduce questo codice in un'implementazione della macchina a stati di IEnumerable (come fa C # per i blocchi iteratori).
Mi piace questa sintassi perché significa ad es. puoi scrivere esattamente lo stesso codice con cui scriveresti " fai cose imperative ora " ;, ad esempio
for i in 0..9 do
for j in someColl do
if i <> j then
printfn "%d" i*j
ma racchiudi quel codice in seq {} e usa 'yield' e il codice diventa invece un IEnumerable pigro.
IEnumerable nats = 0...42 or for generators IEnumerable nats = yield 0...42