Progettare la gamma perfetta letterale


9

Ho pensato a come progettare la gamma "perfetta" letterale se progettassi un linguaggio. Per te che non conosci conosci un intervallo letterale in un'istruzione che rappresenta un intervallo di valori, come 1-4. Sono più comunemente utilizzati nei cicli for / foreach

Sembra che ci siano un paio di problemi da tenere in considerazione

  • Il supporto per range inclusivi ed esclusivi, virando su +1 o -1 agli endpoint sembra un po 'fugly ed incline all'errore.

  • Supporto per stepping, in modo da poter creare un intervallo di numeri pari o dispari, ad esempio

  • Leggibilità, dovrebbe essere immediatamente evidente ciò che l'intervallo letterale descrive

  • Inequivocabile, dovrebbe essere perfettamente inequivocabile ciò che la gamma descrive letteralmente

  • Il valore predefinito dovrebbe probabilmente essere compreso tra inclusivo ed esclusivo poiché è quello che viene utilizzato nella maggior parte dei casi per il looping su array, ecc.

Ad ogni modo, un esempio di intervallo letterale che ho visto è Ruby che ha la forma di 1..3 per un intervallo esclusivo (alla fine) e 1 ... 3 per l'inclusione (alla fine). Puoi anche fare 1..10.step (5). Dopo un'attenta considerazione ho trovato comunque un paio di cose che non mi piacevano di quell'approccio (dalla mia limitata conoscenza del rubino)

  1. Puoi solo descrivere inclusivo ed esclusivo per la fine. Mentre descrive la maggior parte degli scenari sembra un po 'incoerente.

  2. Variando di solo un ulteriore. sembra una ricetta per rendere difficile capire se una gamma è inclusiva o esclusiva. Non ti conosco ma Dot tende a diventare qualcosa di sfocato :)

  3. L'aggiunta di un metodo come la notazione per intervalli sembra mescolare la nozione di letterale con quella di una classe che sembra un po 'incoerente (anche se gli intervalli vengono compilati in una classe)

Comunque, dopo aver riflettuto su diverse alternative. Ho pensato a questo

  • [5..1] 5,4,3,2,1
  • [1..5 [ 1,2,3,4
  • ] 1..5] 2,3,4,5
  • [ 0..5..20] 0,5,10,15,20

e così via. Mi piace perché [normalmente denota un set e questo tipo si adatta a quello, anche se questo in contrasto con un set sarebbe ordinato.

Una cosa di cui sono un po 'sconvolto è rendere obbligatori o meno gli indicatori esclusivi / inclusivi, ovvero se scrivi solo 1..5 il valore predefinito sarebbe 1,2,3,4 poiché è il caso più comune con gli array, ecc. È più facile e più leggibile, ma meno specifico e se dovessi scrivere [1..5 [impari presto su come funzionano.

Cosa ne pensi, ho coperto la maggior parte delle basi, trascurato qualcosa? renderebbe [] obbligatorio? Progetteresti letterali di gamma in modo diverso nel tuo linguaggio di programmazione?

I candidati

  • stile parentesi: [0..10 [ , con step: [0..5..20 [
  • notazione intervallo: [0..10) con passaggio: [0..5..20)
  • esclamativo per esclusivo. 0 ..! 10, con passaggio: 0..5 ..! 20
    • con passi diversi. 0 ..! 20, 5
    • tuttavia, ciò renderebbe il valore predefinito * 0..10 ' incluso-compreso
  • wordy: [da 0 a! 20 per 5]

Devo dire che il mio preferito esteticamente finora è 0 ..! 10 e 0..5 ..! 20 , vorrei solo che l'impostazione predefinita 0..10 su inclusiva esclusiva fosse più logica


2
1,5,10,15,20Spazio 4, 5, 5, 5 ?!
Peter Taylor,

oops :) corretto
Homde

Risposte:


14

Perché inventare ciò che esiste già in matematica?

Notazione a intervalli

Ciò dovrebbe coprire il punto "Unambiguity" in quanto esiste già.

Il tuo unico problema sarebbe definire il passo. Forse qualcos'altro in matematica può aiutare in questo?


3
Ciao, in realtà ho una notazione a intervalli. Tuttavia, ciò che mi ha fatto venir voglia di non usarlo è stato il fatto che non era simmetrico con [e] e usato la parantesi, oltre a non avere passaggi (come hai detto). L'uso della parantesi sembra avere il potenziale per confondere la corrispondenza tra parentesi graffe e preferirei salvarli in espressioni. Usare] e [è uno standard iso e sembrava andare meglio con l'integrazione di stepping, ma questa è solo la mia opinione ovviamente.
Homde

7
@MKO: la tua idea di utilizzare parentesi senza pari (come [1..5[) confonderà gli editor almeno quanto la notazione a intervalli standard.
David Thornley,

2
Hmm, un'altra idea, che ne dici di usare! per, cioè: 1 ..! 5 o 0..5 ..! 20 (con stepping)
Homde

1
@MKO: usare !per escludere il primo o l'ultimo elemento potrebbe essere buono.
FrustratedWithFormsDesigner

8

Hai visto le gamme Haskell? La loro idea di passaggi è simile alla tua (nel mezzo) ma indicata con una differenza sintattica (dalla risposta di @ luqui ):

[1,2..10] = [1,2,3,4,5,6,7,8,9,10]
[1,3..10] = [1,3,5,7,9]
[4,3..0]  = [4,3,2,1,0]
[0,5..]   = [0,5,10,15,20,25,30,35...  -- infinite
[1,1..]   = [1,1,1,1,1,1,1,1,1,1,1...  -- infinite

Trovo questa notazione molto intuitiva: inizi a elencare e salti sul corpo per segnare dove dovrebbe finire.

Non copre il caso di "esclusivo", ma francamente, preferirei essere chiaro sul comportamento una volta (specificare quale limite è inclusivo e quale è esclusivo) e si aspetta che l'utente effettui aggiustamenti a meno che la sintassi non sia estremamente chiara (e non confonde gli editor agnostici di lingua).


5

Dovresti leggere le comprensioni degli elenchi nelle lingue che li offrono.

Python, ad esempio, copre i tuoi casi abbastanza bene con la range()funzione e la comprensione dell'elenco per casi troppo complessi con cui esprimersi range().


2

Credo che la tua notazione sia ben lontana dall'essere inequivocabile. Intuitivamente, [0..5..20]non mi sembra un intervallo con larghezza del gradino = 5. In alcuni casi angolari fallisce anche: che ne dici di esprimere il set (0,2) - [0..2..2]o cosa dovrei mettere nel mezzo?

Penso che la notazione di slice di Python sia un approccio solido: [start:end:step](il passaggio è facoltativo).

Se hai davvero bisogno di supporto per intervalli esclusivi e inclusivi, utilizzerei la notazione di intervallo standard (cioè usando (e [) a meno che ciò non introduca ambiguità sintattiche nella tua lingua.


1
per quanto riguarda la notazione "standard", le scuole europee insegnano [], [[, ]]e ][, senza parentesi ... e la nostra norma è meglio, naturalmente;)
Matthieu M.

@Matthieu: In realtà, qui nei Paesi Bassi (che si trova in Europa), ci hanno insegnato anche quella notazione standard.
Frits

1

Penso che quando si imposta un terzo valore di incremento, è meglio aggiungere questo alla fine, piuttosto che al centro, poiché questo è un valore facoltativo e sembra più intuitivo per i programmatori esperti che aggiungere un terzo argomento opzionale nel mezzo .

quindi invece di [1..5..20] potresti fare qualcosa come [1..20] [5] o [1..20,5]


Questo è un punto valido e forse una questione di gusti, mi è sembrato semplicemente più facile pensare "1 passaggio da 5 a 20" anziché ", da 1 a 2, con passaggio 5" utilizzando [1..20] [5] sembra un po 'ingombra ma forse l'approccio virgola sarebbe praticabile. Gradirei più feedback su questo
Homde

1
  • [1..5 [1,2,3,4
  • ] 1..5] 2,3,4,5
  • ] 1..5 [2,3,4

Perché non usare solo [1..4], [2..5], [2..4]? Gli intervalli esclusi non offrono molti vantaggi. Non è necessario scrivere MIN + 1 o MAX-1, sì, ma non lo vietano comunque. Troppa variazione, imho. La mia lingua preferita, scala, ha (da 1 a 3) e (da 1 a 3) [= (da 1 a 2)] ma all'inizio mi ha confuso. Ora uso sempre "da x a y" e so quindi che l'opzione che non utilizzo è quella di esclusione, ma ovviamente non beneficio di un'opzione che non utilizzo.

  • [5..1] 5,4,3,2,1

è ovviamente (da 1 a MAX) (x => y = (MAX + 1) - x) ma è molto più semplice e poco intuitivo.

  • [0..5..20] 0,5,10,15,20

è ovviamente (da 0 a 4) (x => y = x * 5) non è così tanto boilerplate. Discutibile.


Il vantaggio principale dell'esclusione di intervalli, afaik, è che il numero di elementi è la differenza degli endpoint.
Justin L.,

@JustinL .: 5-1 è 4 nella mia algebra ma contiene 3 elementi, esclusi i limiti: 2, 3, 4.
Utente sconosciuto

1

Che dire di qualcosa del genere:

  • [5..1] 5,4,3,2,1
  • [1..5] [i, e] 1,2,3,4
  • [5..1] [i, e] 5.4,3,2
  • [1..5] [e, i] 2,3,4,5
  • [1..5] [e, e] 2,3,4
  • [0..20] di 5 0,5,10,15,20

La ie enella seconda coppia di parentesi quadre indica se l'inizio o la fine dell'intervallo sono inclusivi o esclusivi (oppure è possibile utilizzare incle exclse si desidera essere più chiari). la by 5indica l'intervallo di passo. Il primo e l'ultimo esempio sono comprensivi del primo e dell'ultimo valore, quindi ho omesso il [i,i], che penso sarebbe un comportamento predefinito assunto OK.

I valori predefiniti potrebbero essere [i,i]per l'identificatore inclusivo / esclusivo e by 1per l'identificatore del passaggio.

Normalmente avrei suggerito la notazione standard che coinvolge (e [come menzionato da @Dan McGrath, ma sono d'accordo che nel codice questo potrebbe sembrare confuso.


Qualcuno può spiegare il downvote?
FrustratedWithFormsDesigner

Non ho visto nulla di palesemente sbagliato . Ho votato per contrastare il downvote.
Berin Loritsch,

1

E il vincitore è

Ci scusiamo per aver scelto la mia soluzione, apprezzo molto tutti i commenti e i feedback e ti prego di criticare questa soluzione se trovi qualcosa di sbagliato in essa

Quindi ho deciso di andare con:

0..5           = 0,1,2,3,5
0..5..10       = 0,5,10
..3            = 0,1,3
!0..!5         = 1,2,3,4
3..            = 3 to infinity

segmented ranges
-
0..5,..5..20   = 0,1,2,3,4,5,10,15,20
0..3,10..5..20 = 0,1,2,3,10,15,20

Come puoi vedere inclusivo è il valore predefinito su entrambi i sensi, è ciò che ha intuitivamente più senso soprattutto quando si utilizza il passo. Puoi usare ! per rendere esclusivo un fine.

Il rovescio della medaglia è che normalmente si desidera utilizzare l'esclusivo quando si lavora su un array, ma, di nuovo, la maggior parte delle volte si dovrebbe probabilmente usare qualcosa come for-each in quei casi. Se hai davvero bisogno di lavorare contro l'indice, il parser potrebbe riconoscere quando potresti aver dimenticato il marcatore di esclusione alla fine ed emettere un avviso

Sono andato con l'uso di .. su entrambi i lati della variabile step invece di usare la virgola o qualsiasi altra cosa poiché è quello che sembrava più pulito e spero sia il più leggibile.

Ho anche inserito una sintassi con le virgole per essere in grado di creare intervalli in cui parti diverse hanno passaggi diversi


Sembra a posto tranne quando si specifica il passaggio. Penso che sarebbe più pulito come [0..10 per 5]. L'intervallo segmentato potrebbe essere [0..5, ..20 per 5], ecc. Si potrebbe anche specificare [numitems dal primo passo], che (a differenza delle altre forme) potrebbe consentire una dimensione del passo pari a zero.
supercat,

0

Non userei il modulo '[1..5 [' per uno degli stessi motivi per cui eviteresti di mescolare parentesi e parentesi graffe - confonderà la maggior parte delle parentesi graffe degli editor esistenti. Forse usa un pennarello all'interno delle parentesi graffe, come '[1 .. | 5]'.

L'altra cosa da considerare è il comportamento dei metodi per ottenere i limiti. Ad esempio, 'inizio' / 'fine' vs. 'primo' / 'ultimo' vs. 'min' / 'max'. Devono essere sani di mente sia per i limiti inclusivi che per quelli esclusivi, così come quelli con una dimensione del gradino.


0

Ruby ha una notazione e un oggetto Range che funziona. In sostanza si presenta così:

1..5  # range 1,2,3,4,5

Con Ruby, la dimensione del passo non è una funzione dell'intervallo, ma piuttosto una funzione di iterazione attraverso l'intervallo. Potremmo usare la stessa gamma sopra e iterarla diversamente se volessimo:

(1..5).step(3) { |x| puts x }
(1..5).step(2) { |x| puts x }

Quindi, ecco alcune cose che potresti voler considerare:

  • L'aggiunta del supporto linguistico per endpoint inclusivi / esclusivi può essere problematico. Se tutti gli intervalli sono inclusi (scelta di Ruby), gli sviluppatori regoleranno di conseguenza gli endpoint dell'intervallo. Come si rappresentano l'inclusione o l'esclusività degli endpoint in un modo che è sia visivamente inequivocabile che inequivocabile con una semplice grammatica del parser?
  • Stai usando l'intervallo per qualcosa di più che iterare? Esempi comuni includono confronti di intervalli, splicing, valori di confronto di intervalli. In tal caso, come si rappresentano tali possibilità? (Vedi il link alla classe Range per idee su ciascuno di questi esempi.)

A proposito, le gamme sono piuttosto belle se si consente loro di essere incluse in un'istruzione switch come fa Ruby:

switch(myval)
    when 0..33 then puts "Low"
    when 34..66 then puts "Medium"
    when 67..100 then puts "High"
end

Non sto dicendo che l'oggetto gamma di Ruby sia la fine e sia tutto, ma è un'implementazione funzionante del concetto di cui stai parlando. Gioca con esso per vedere cosa ti piace, non ti piace e farebbe diversamente.


Leggi attentamente la domanda, OP è già a conoscenza delle gamme Ruby:Anyways, one example of range literal I've seen is Ruby which is in the form of 1..3 for an exclusive (on the end) range and 1...3 for inclusive (on the end). You can also do 1..10.step(5).
FrustratedWithFormsDesigner

0

Una soluzione che certamente prenderei in considerazione è l'utilizzo del sovraccarico dell'operatore per consentire ad es

1+[0..3]*5

Non sarebbe necessariamente immediatamente trasparente per tutti, ma una volta che si fermano e pensano che spero che la maggior parte dei programmatori lo capisca, e le persone che usano regolarmente la lingua semplicemente lo imparerebbero come un linguaggio.

Per chiarire, il risultato sarebbe [1, 6, 11, 16], sollevando la moltiplicazione e quindi l'aggiunta oltre l'intervallo. Non mi ero reso conto che potrebbe essere ambiguo per gli utenti di Python; Penso agli intervalli come sottoinsiemi di ordini totali piuttosto che come elenchi. e ripetere un set non ha senso.


2
Molto ambiguo. list expression * 5potrebbe anche significare "ripetere il valore di list expression5 volte", come in Python.
nikie,

Questo è molto strano e non sono sicuro di cosa sarebbe ... 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3? 1,3,6,9,12? 5,10,15? qualcos'altro, forse? Ad ogni modo, trovo questa notazione del tutto controintuitiva. Sembra che sia forse una sorta di strana operazione del puntatore C ...
FrustratedWithFormsDesigner
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.