Entwerfen des perfekten Bereichs wörtlich

9

Ich habe darüber nachgedacht, wie ich das "perfekte" Bereichsliteral entwerfen würde, wenn ich eine Sprache entwerfen würde. Für Sie, die kein Bereichsliteral in einer Anweisung kennen, die einen Wertebereich wie 1-4 darstellt. Sie werden am häufigsten in for / foreach-Schleifen verwendet

Es scheint ein paar Probleme zu geben, die man berücksichtigen sollte

  • Die Unterstützung für inklusive und exklusive Bereiche, das Anheften von +1 oder -1 an Endpunkte, scheint etwas umständlich und fehleranfällig zu sein.

  • Unterstützung für das Steppen, sodass Sie beispielsweise eine Reihe von geraden oder ungeraden Zahlen erstellen können

  • Lesbarkeit sollte leicht ersichtlich sein, was das Bereichsliteral beschreibt

  • Eindeutigkeit, es sollte absolut eindeutig sein, was das Bereichsliteral beschreibt

  • Die Standardeinstellung sollte wahrscheinlich von inklusive bis exklusiv sein, da dies in den meisten Fällen zum Durchlaufen von Arrays usw. verwendet wird.

Ein Beispiel für ein Bereichsliteral, das ich gesehen habe, ist Ruby, das in Form von 1..3 für einen exklusiven Bereich (am Ende) und 1 ... 3 für inklusive (am Ende) vorliegt. Sie können auch 1..10.Schritt (5) ausführen. Nach sorgfältiger Überlegung fand ich jedoch einige Dinge, die mir an diesem Ansatz nicht gefallen haben (aufgrund meiner begrenzten Kenntnisse über Rubin).

  1. Sie können nur inklusive und exklusiv für das Ende beschreiben. Während die meisten Szenarien beschrieben werden, scheint es ein wenig inkonsistent zu sein.

  2. Variiert nur um einen zusätzlichen. scheint ein Rezept zu sein, um schwer zu erkennen, ob ein Sortiment inklusive oder exklusiv ist. Ich weiß nichts über dich, aber Punkte neigen dazu, etwas verschwommen zu werden :)

  3. Das Hinzufügen einer Methode wie der Notation für Bereiche scheint den Begriff eines Literal mit dem einer Klasse zu vermischen, was etwas inkonsistent erscheint (selbst wenn Bereiche zu einer Klasse kompiliert werden).

Wie auch immer, nachdem ich über verschiedene Alternativen nachgedacht habe. Ich habe mir das ausgedacht

  • [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

und so weiter. Ich mag es, weil [normalerweise ein Set denoniert und dies irgendwie dazu passt, obwohl dies im Gegensatz zu einem Set bestellt werden würde.

Eine Sache, über die ich ein bisschen hin und her gerissen bin, ist, die exklusiven / inklusiven Indikatoren obligatorisch zu machen oder nicht, dh wenn Sie nur 1..5 schreiben, wäre der Standardwert 1,2,3,4, da dies der häufigste Fall bei Arrays usw. Ist Es ist einfacher und lesbarer, aber weniger spezifisch, und wenn Sie schreiben müssen [1..5 [, lernen Sie früh, wie sie funktionieren.

Also, was denkst du, habe ich die meisten Grundlagen abgedeckt, etwas übersehen? Würden Sie das [] obligatorisch machen? Würden Sie Bereichsliterale in Ihrer Programmiersprache anders gestalten?

Kandidaten

  • Klammerstil: [0..10 [ , mit Schritt: [0..5..20 [
  • Intervallnotation: [0..10) mit Schritt: [0..5..20)
  • Ausruf für exklusiv. 0 ..! 10, mit Schritt: 0..5 ..! 20
    • mit anderem Schritt. 0 ..! 20, 5
    • Dies würde jedoch die Standardeinstellung * 0..10 ' inklusive-inklusive machen
  • wortreich: [0 bis! 20 mal 5]

Ich muss sagen, dass mein bisheriger ästhetischer Favorit 0 ..! 10 und 0..5 ..! 20 ist. Ich wünschte nur, die Standardeinstellung 0..10 für inklusive-exklusiv wäre logischer

Homde
quelle
2
1,5,10,15,20Lücke 4, 5, 5, 5?!
Peter Taylor
oops :) korrigiert
Homde

Antworten:

14

Warum erfinden, was es in der Mathematik bereits gibt?

Intervall-Notation

Das sollte Ihren Punkt "Eindeutigkeit" abdecken, wie er bereits existiert.

Ihr einziges Problem wäre die Definition des Schrittes. Vielleicht kann etwas anderes in der Mathematik dabei helfen?

Dan McGrath
quelle
3
Hallo, ich habe eigentlich über Intervallnotation. Was mich jedoch dazu brachte, es nicht verwenden zu wollen, war die Tatsache, dass es nicht symmetrisch zu [und] war und Paranthesis verwendete sowie keine Schritte hatte (wie Sie erwähnen). Die Verwendung von Klammern scheint das Potenzial zu haben, die Übereinstimmung von Klammern zu verwirren, und ich würde sie lieber in Ausdrücken speichern. Die Verwendung von] und [ist ein ISO-Standard und schien mit der Integration von Stepping besser zu gehen, aber das ist natürlich nur meine Meinung.
Homde
7
@MKO: Ihre Idee, nicht übereinstimmende Klammern (wie [1..5[) zu verwenden, verwirrt die Editoren mindestens so sehr wie die Standardintervallnotation.
David Thornley
2
Hmm, eine andere Idee, was ist mit! für, dh: 1 ..! 5 oder 0..5 ..! 20 (mit Schritt)
Homde
1
@MKO: Das !Ausschließen des ersten oder letzten Elements kann gut sein.
FrustratedWithFormsDesigner
8

Haben Sie Haskell-Bereiche gesehen? Ihre Idee für Schritte ähnelt Ihrer (in der Mitte), wird jedoch mit einem syntaktischen Unterschied angegeben (aus der Antwort von @ 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

Ich finde diese Notation sehr intuitiv: Sie beginnen mit der Aufzählung und überspringen den Körper, um zu markieren, wo er enden soll.

Es wird nicht der Fall für "exklusiv" behandelt, aber ehrlich gesagt möchte ich das Verhalten lieber einmal klarstellen (angeben, welche Grenze inklusive und welche exklusiv ist), und erwartet, dass der Benutzer Anpassungen vornimmt, es sei denn, die Syntax ist extrem klar (und verwirrt sprachunabhängige Redakteure nicht).

Matthieu M.
quelle
5

Sie sollten über Listenverständnisse in Sprachen lesen, die sie anbieten.

Python zum Beispiel deckt Ihre Fälle ziemlich gut mit der range()Funktion und dem Listenverständnis für Fälle ab, die zu komplex sind, um sie auszudrücken range().

S.Lott
quelle
2

Ich glaube, Ihre Notation ist weit davon entfernt, eindeutig zu sein. Intuitiv [0..5..20]sieht es für mich nicht wie ein Bereich mit Schrittweite = 5 aus. In einigen Eckfällen schlägt es sogar fehl: Was ist mit dem Ausdrücken der Menge (0,2) - [0..2..2]oder was soll ich in die Mitte setzen?

Ich denke, dass Pythons Slice-Notation ein solider Ansatz ist: [start:end:step](Schritt ist optional).

Wenn Sie wirklich Unterstützung für exklusive und inklusive Bereiche benötigen, würde ich die Standardbereichsnotation verwenden (dh (und verwenden [), es sei denn, dies führt zu syntaktischen Mehrdeutigkeiten in Ihrer Sprache.

Alexander Gessler
quelle
1
in Bezug auf die „Standard“ Notation, lehren europäische Schulen [], [[, ]]und ][, keine Klammer ... und unser Standard ist besser, natürlich;)
Matthieu M.
@Matthieu: Eigentlich hier in den Niederlanden (das ist in Europa), waren wir auch , dass die Standardnotation gelehrt.
Frits
1

Ich denke, wenn Sie einen dritten Inkrementwert festlegen, ist es besser, diesen als das Ende und nicht die Mitte hinzuzufügen, da dies ein optionaler Wert ist und erfahrenen Programmierern intuitiver erscheint, als ein optionales drittes Argument in der Mitte hinzuzufügen .

Anstelle von [1..5..20] könnten Sie also etwas wie [1..20] [5] oder [1..20,5] tun.

Canuteson
quelle
Das ist ein gültiger Punkt und vielleicht eine Frage des Geschmacks. Es schien mir nur einfacher zu sein, "1 Schritt 5 bis 20" zu denken, als "von 1 bis 2, mit Schritt 5" unter Verwendung von [1..20]. [5] scheint etwas überladen zu sein, aber vielleicht wäre der Komma-Ansatz sinnvoll. Ich würde mich über mehr Feedback dazu
freuen
1
  • [1..5 [1,2,3,4
  • ] 1..5] 2,3,4,5
  • ] 1..5 [2,3,4

Warum nicht einfach [1..4], [2..5], [2..4] verwenden? Das Ausschließen von Bereichen bietet nicht viel Nutzen. Sie müssen nicht MIN + 1 oder MAX-1 schreiben, ja, aber sie verbieten es trotzdem nicht. Zu viel Abwechslung, imho. Meine Sprache der Wahl, Scala, hat (1 bis 3) und (1 bis 3) [= (1 bis 2)], aber es hat mich am Anfang nur verwirrt. Jetzt benutze ich immer 'x bis y' und weiß daher, dass die Option, die ich nicht benutze, die ausschließende ist, aber natürlich profitiere ich nicht von einer Option, die ich nicht benutze.

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

ist natürlich (1 bis MAX) (x => y = (MAX + 1) - x), aber das ist viel Boilerplate und nicht benutzerfreundlich.

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

ist natürlich (0 bis 4) (x => y = x * 5) ist nicht so sehr Boilerplate. Umstritten.

Benutzer unbekannt
quelle
Der Hauptvorteil des Ausschlusses von Bereichen, afaik, besteht darin, dass die Anzahl der Elemente die Differenz der Endpunkte ist.
Justin L.
@ JustinL.: 5-1 ist 4 in meiner Algebra, enthält aber 3 Elemente, ausgenommen die Grenzen: 2, 3, 4.
Benutzer unbekannt
1

Was ist mit so etwas:

  • [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] um 5 0,5,10,15,20

Das iund eim zweiten Paar eckiger Klammern gibt an, ob der Anfang oder das Ende des Bereichs inklusive oder exklusiv ist (oder ob Sie ihn verwenden könnten inclund exclob Sie klarer sein möchten). Das by 5gibt das Schrittintervall an. Das erste und das letzte Beispiel enthalten den ersten und den letzten Wert, daher habe ich das weggelassen [i,i], was meiner Meinung nach ein OK-angenommenes Standardverhalten wäre.

Standardwerte können [i,i]für den Inklusiv- / Exklusivspezifizierer und by 1für den Schrittspezifizierer sein.

Normalerweise hätte ich die Standard - Notation vorgeschlagen beteiligt (und [wie von @ Dan McGrath erwähnt, aber ich stimme zu, dass dies in Code verwirrend aussehen könnte.

FrustratedWithFormsDesigner
quelle
Kann jemand die Ablehnung erklären?
FrustratedWithFormsDesigner
Ich habe offensichtlich nichts Falsches gesehen . Ich habe gestimmt, um dem Abstimmen entgegenzuwirken.
Berin Loritsch
1

Und der Gewinner ist

Es tut mir leid, dass Sie sich für meine eigene Lösung entschieden haben. Ich freue mich über alle Kommentare und Rückmeldungen und kritisiere diese Lösung, wenn Sie etwas falsches daran finden

Also entschied ich mich für:

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

Wie Sie sehen können, ist Inklusiv die Standardeinstellung für beide Sinne. Dies ist intuitiv am sinnvollsten, insbesondere bei Verwendung von Stepping. Sie können verwenden! ein Ende exklusiv machen.

Der Nachteil ist, dass Sie normalerweise exklusiv verwenden möchten, wenn Sie gegen ein Array arbeiten, aber andererseits sollten Sie in diesen Fällen wahrscheinlich meistens so etwas wie für jeden verwenden. Wenn Sie wirklich wirklich gegen den Index arbeiten müssen, kann der Parser erkennen, wenn Sie möglicherweise die Ausschlussmarkierung am Ende vergessen haben, und eine Warnung ausgeben

Ich habe auf beiden Seiten der Schrittvariablen ... verwendet, anstatt Komma oder irgendetwas anderes zu verwenden, da dies am saubersten aussah und ich hoffe, dass es am besten lesbar ist.

Ich habe auch eine Syntax mit Kommas eingegeben, um Bereiche erstellen zu können, in denen verschiedene Teile unterschiedliche Schritte haben

Homde
quelle
Es scheint in Ordnung zu sein, außer wenn der Schritt angegeben wird. Ich denke das wäre sauberer als [0..10 mal 5]. Der segmentierte Bereich könnte [0..5, ..20 mal 5] usw. sein. Man könnte auch [numitems from first by step] angeben, was (im Gegensatz zu den anderen Formen) eine Schrittgröße von Null ermöglichen könnte.
Supercat
0

Ich würde das Formular '[1..5 [' nicht aus dem gleichen Grund verwenden, aus dem Sie das Mischen von Parens und Klammern vermeiden würden - es wird die Klammerübereinstimmung der meisten vorhandenen Editoren verwirren. Verwenden Sie möglicherweise einen Marker in den geschweiften Klammern, z. B. '[1 .. | 5]'.

Die andere zu berücksichtigende Sache ist das Verhalten von Methoden, um die Grenzen zu erreichen. Zum Beispiel 'begin' / 'end' vs. 'first' / 'last' vs. 'min' / 'max'. Sie müssen sowohl für inklusive als auch für exklusive Limits sowie für solche mit einer Schrittgröße vernünftig sein.

AShelly
quelle
0

Ruby hat eine Notation und ein Range- Objekt, das funktioniert. Im Wesentlichen sieht es so aus:

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

Bei Ruby hängt die Schrittgröße nicht vom Bereich ab, sondern vom Durchlaufen des Bereichs. Wir könnten den gleichen Bereich oben verwenden und ihn anders durchlaufen, wenn wir wollten:

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

Hier sind also Dinge, die Sie berücksichtigen sollten:

  • Das Hinzufügen von Sprachunterstützung für inklusive / exklusive Endpunkte kann problematisch sein. Wenn alle Bereiche inklusive sind (Rubys Wahl), passen die Entwickler die Endpunkte des Bereichs entsprechend an. Wie stellen Sie die Inklusivität oder Exklusivität der Endpunkte auf eine Weise dar, die mit einer einfachen Parser-Grammatik sowohl visuell eindeutig als auch eindeutig ist?
  • Verwenden Sie den Bereich nicht nur zum Iterieren? Häufige Beispiele sind Bereichsvergleiche, Spleißen und Werte in Bereichsvergleichen. Wenn ja, wie stellen Sie diese Möglichkeiten dar? (Ideen zu den einzelnen Beispielen finden Sie unter dem Link zur Range-Klasse.)

Übrigens sind Bereiche ziemlich nett, wenn Sie zulassen, dass sie wie Ruby in einer switch-Anweisung enthalten sind:

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

Ich sage nicht, dass Rubys Bereichsobjekt das Ende aller und alles ist, aber es ist eine funktionierende Implementierung des Konzepts, von dem Sie sprechen. Spielen Sie damit, um zu sehen, was Sie mögen, nicht mögen und was Sie anders machen würden.

Berin Loritsch
quelle
Lesen Sie die Frage sorgfältig durch, OP kennt bereits Ruby-Bereiche: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

Eine Lösung, die ich sicherlich in Betracht ziehen würde, ist die Verwendung von Operatorüberladung, um z

1+[0..3]*5

Es wäre nicht unbedingt sofort für alle transparent, aber wenn sie aufhören und denken, ich hoffe, die meisten Programmierer würden es verstehen, und Leute, die die Sprache regelmäßig verwenden, würden sie einfach als Redewendung lernen.

Zur Verdeutlichung wäre das Ergebnis [1, 6, 11, 16], die Multiplikation und dann die Addition über den Bereich anzuheben. Ich hatte nicht bemerkt, dass es für Python-Benutzer nicht eindeutig sein könnte. Ich stelle mir Bereiche eher als Teilmengen der Gesamtbestellungen als als Listen vor. und das Wiederholen eines Satzes macht keinen Sinn.

Peter Taylor
quelle
2
Sehr vieldeutig. list expression * 5könnte auch "den Wert list expression5 mal wiederholen" bedeuten , wie es in Python der Fall ist.
Nikie
Das sieht sehr seltsam aus und ich bin mir nicht sicher, was das sein würde ... 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? vielleicht noch etwas? In jedem Fall finde ich diese Notation völlig eingängig. Es sieht so aus, als wäre es vielleicht eine seltsame C-Zeiger-Operation ...
FrustratedWithFormsDesigner