Проектирование идеального диапазона буквально

9

Я думал о том, как бы я занялся проектированием «идеального» литерала диапазона, если бы я занимался дизайном языка. Для вас, кто не знает, вы знаете литерал диапазона в выражении, представляющем диапазон значений, например 1-4. Они чаще всего используются в циклах for / foreach

Кажется, есть пара вопросов, которые следует учитывать

  • Поддержка инклюзивных и эксклюзивных диапазонов, привязка к +1 или -1 к конечным точкам кажется немного ошибочной и подверженной ошибкам.

  • Поддержка степпинга, так что вы можете сделать диапазон четных или нечетных чисел, например

  • Читаемость, должно быть очевидно, что описывает диапазон

  • Однозначность, должно быть совершенно однозначно то, что описывает литерал диапазона

  • Значение по умолчанию должно быть от включающего к исключительному, поскольку именно это используется в большинстве случаев для циклического перебора массивов и т. Д.

В любом случае, одним из примеров литерала диапазона, который я видел, является Ruby, который имеет форму 1..3 для исключительного (в конце) диапазона и 1 ... 3 для включающего (в конце). Вы также можете сделать 1..10.step (5). После тщательного рассмотрения я обнаружил, однако, пару вещей, которые мне не нравились в этом подходе (из моего ограниченного знания рубина)

  1. Вы можете описать только включительно и эксклюзивно для конца. При описании большинства сценариев это выглядит немного противоречивым.

  2. Варьируется просто доп. Похоже, это рецепт, из-за которого трудно понять, является ли диапазон включительным или эксклюзивным. Я не знаю о вас, но точки имеют тенденцию становиться чем-то вроде размытия :)

  3. Добавление метода, такого как нотация для диапазонов, кажется, смешивает понятие литерала с понятием класса, который кажется немного противоречивым (даже если диапазоны компилируются в класс)

В любом случае, после обдумывания разных альтернатив. Я придумал это

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

и так далее. Мне это нравится, потому что [обычно денонсирует набор, и это как бы вписывается в это, хотя это в отличие от набора будет упорядоченным.

Одна вещь, о которой я немного волнуюсь, - это сделать обязательными или нет обязательные или исключительные индикаторы, т.е. если вы пишете только 1..5, по умолчанию будет 1,2,3,4, так как это наиболее распространенный случай с массивами и т. Д. Это легче и более читабельно, но менее конкретно, и если вам пришлось писать [1..5 [вы рано узнаете о том, как они работают.

Так что вы думаете, я охватил большинство баз, что-то упустил? Вы бы сделали [] обязательным? Будете ли вы по-разному проектировать литералы диапазона на вашем языке программирования?

Кандидаты

  • стиль скобок: [0..10 [ , с шагом: [0..5..20 [
  • обозначение интервала: [0..10) с шагом: [0..5..20)
  • Восклицательный для эксклюзивных. 0 ..! 10, с шагом: 0..5 ..! 20
    • с другим шагом. 0 ..! 20, 5
    • однако это сделало бы значение по умолчанию * 0..10 ' включительно включительно
  • многословно: [от 0 до! 20 на 5]

Я должен сказать, что мой любимый эстетически до сих пор 0 ..! 10 и 0..5 ..! 20 , я просто хочу, чтобы по умолчанию 0..10 для включительно-эксклюзивного было бы более логичным

Homde
источник
2
1,5,10,15,20Разрыв 4, 5, 5, 5 ?!
Питер Тейлор
упс :) исправлено
Homde

Ответы:

14

Зачем изобретать то, что уже существует в математике?

Интервальная запись

Это должно охватывать ваш пункт «Однозначность», поскольку он уже существует.

Ваша единственная проблема будет определять шаг. Может быть, что-то еще в математике может помочь с этим?

Дэн МакГрат
источник
3
Привет, я на самом деле о интервальной записи. Однако, то, что заставило меня не хотеть использовать это, было фактом, что это не было симметрично и с [и) и использовало paranthesis так же как не имея шагов (как Вы упоминаете). Использование парантеза может привести к путанице в скобках, и я бы предпочел сохранить их в выражениях. Использование] и [является стандартом iso и, кажется, лучше интегрирует степпинг, но это, конечно, мое мнение.
Homde
7
@MKO: Ваша идея использовать непревзойденные скобки (например [1..5[), запутает редакторов, по крайней мере, так же, как стандартные интервальные обозначения.
Дэвид Торнли
2
Хм, другая идея, как насчет использования! для, то есть: 1 ..! 5 или 0..5 ..! 20 (со степпингом)
Homde
1
@MKO: Использование !для исключения первого или последнего элемента может быть хорошо.
FrustratedWithFormsDesigner
8

Вы видели диапазоны Haskell? Их идея для шагов похожа на вашу (в середине), но обозначена синтаксической разницей (из ответа @ 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

Я считаю эту запись очень интуитивной: вы начинаете перечислять и пропускаете тело, чтобы отметить, где оно должно заканчиваться.

Это не относится к случаю «исключительного», но, честно говоря, я бы лучше однажды прояснил поведение (укажите, какая граница является включающим, а какой - исключительным) и ожидает, что пользователь внесет коррективы, если синтаксис не предельно ясен (и не смущает языковых редакторов).

Матье М.
источник
5

Вы должны прочитать о списках на языках, которые их предлагают.

Например, Python очень хорошо покрывает ваши случаи с помощью range()функции и понимания списка для случаев, которые слишком сложны для выражения range().

С. Лотт
источник
2

Я считаю, что ваша запись далеко не однозначна. Интуитивно, [0..5..20]мне не кажется, что диапазон с шириной шага = 5. В некоторых угловых случаях он даже не срабатывает: как насчет выражения множества (0,2) [0..2..2]или что я должен поместить в середину?

Я думаю, что нотация срезов Python - это надежный подход [start:end:step](шаг необязательный).

Если вам действительно нужна поддержка эксклюзивных и инклюзивных диапазонов, я бы использовал стандартную нотацию диапазонов (т. Е. Используя (и [), если это не вводит синтаксические неоднозначности в вашем языке.

Александр Гесслер
источник
1
относительно «стандартного» нотации, европейские школы не учат [], [[, ]]и ][, не скобку ... и наш стандарт лучше, конечно;)
Матье М.
@Matthieu: На самом деле, здесь , в Нидерландах (который находится в Европе), мы также учили , что стандартные обозначения.
Фритс
1

Я думаю, что когда вы устанавливаете третье значение приращения, вам лучше добавить это конец, а не середину, поскольку это необязательное значение, и оно кажется более интуитивным для опытных программистов, чем добавление необязательного третьего аргумента в середине ,

поэтому вместо [1..5..20] вы можете сделать что-то вроде [1..20] [5] или [1..20,5]

Canuteson
источник
Это верный момент и, возможно, дело вкуса, мне просто показалось, что было бы легче думать «1 шаг 5–20», чем «от 1 до 2 с шагом 5», используя [1..20] [5] кажется немного загроможденным, но, возможно, подход с запятыми был бы жизнеспособным. Я был бы признателен за дополнительную информацию об этом
Homde
1
  • [1..5 [1,2,3,4
  • ] 1..5] 2,3,4,5
  • ] 1..5 [2,3,4

Почему бы просто не использовать [1..4], [2..5], [2..4]? Исключая диапазоны не дают большой выгоды. Вам не нужно писать MIN + 1 или MAX-1, да, но они все равно не запрещают это. Слишком много вариаций, имхо. Мой язык по выбору, scala, имеет (от 1 до 3) и (от 1 до 3) [= (от 1 до 2)], но в начале меня просто смутило. Теперь я всегда использую 'x to y' и поэтому знаю, что опция, которую я не использую, является исключающей, но, конечно, я не получаю пользу от опции, которую я не использую.

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

конечно (от 1 до MAX) (x => y = (MAX + 1) - x), но это значительно и не удобно для пользователя.

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

это, конечно (от 0 до 4) (х => у = х * 5) не так много шаблонно. Спорные.

Пользователь неизвестен
источник
Основное преимущество исключения диапазонов, afaik, заключается в том, что количество элементов является разностью конечных точек.
Джастин Л.
@JustinL .: 5-1 - это 4 в моей алгебре, но содержит 3 элемента, исключая границы: 2, 3, 4.
пользователь неизвестен
1

Как насчет чего-то вроде этого:

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

Символ « iи» eво второй паре квадратных скобок указывает, является ли начало или конец диапазона включающим или исключительным (или вы можете использовать его incl, и exclесли вы хотите быть более ясным). by 5указывает интервал шаговый. Первый и последний пример включают первое и последнее значение, поэтому я пропустил [i,i], что, я думаю, будет нормальным поведением по умолчанию.

Значения по умолчанию могут быть [i,i]для включающего / исключающего спецификатора и by 1для спецификатора шага.

Обычно я бы предложил стандартные обозначения с участием (и [как было упомянуто @Dan McGrath, но я согласен , что в коде это может выглядеть запутанным.

FrustratedWithFormsDesigner
источник
Кто-нибудь может объяснить отрицательный голос?
FrustratedWithFormsDesigner
Я не видел ничего явно неправильного . Я проголосовал против противодействия.
Берин Лорич
1

И победителем становится

Извините за выбор собственного решения, я действительно ценю все комментарии и отзывы, и, пожалуйста, критикуйте это решение, если вы обнаружите, что с ним что-то не так.

Поэтому я решил пойти с:

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

Как вы можете видеть, инклюзивным является значение по умолчанию в обоих смыслах, это то, что наиболее интуитивно понятно, особенно при использовании степпинга. Ты можешь использовать ! сделать конец эксклюзивным.

Недостатком является то, что обычно вы хотите использовать исключение при работе с массивом, но, опять же, в большинстве случаев вам, вероятно, следует использовать что-то вроде for-each в этих случаях. Если вам действительно нужно работать с индексом, парсер может распознать, когда вы, возможно, забыли маркер исключения в конце, и выдать предупреждение

Я пошел с использованием .. с обеих сторон переменной шага вместо запятой или чего-то еще, потому что это выглядело наиболее чисто, и я надеюсь, что это наиболее читабельно.

Я также добавил синтаксис с запятыми, чтобы иметь возможность создавать диапазоны, где разные части имеют разные шаги

Homde
источник
Кажется, все в порядке, кроме как при указании шага. Я думаю, что было бы чище, как [0..10 на 5]. Сегментированный диапазон может быть [0..5, ..20 на 5] и т. Д. Можно также указать [numitems от первого к шагу], что (в отличие от других форм) может позволить нулевой размер шага.
суперкат
0

Я бы не стал использовать форму «[1..5 [» по одной и той же причине, по которой вы избегали бы смешивать скобки и скобки - это может привести к путанице в скобках большинства существующих редакторов. Возможно, используйте маркер внутри фигурных скобок, например «[1 .. | 5]».

Другая вещь, которую следует учитывать, - это поведение методов, чтобы получить пределы. Например, «начало» / «конец» против «первый» / «последний» против «мин» / «макс». Они должны быть нормальными как для инклюзивных, так и для эксклюзивных ограничений, а также для тех, у кого размер шага.

AShelly
источник
0

У Ruby есть нотация и объект Range, который работает. По сути это выглядит так:

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

В Ruby размер шага не является функцией диапазона, а скорее функцией итерации по диапазону. Мы могли бы использовать тот же диапазон выше и проходить по нему по-разному, если бы мы хотели:

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

Итак, вот что вы можете рассмотреть:

  • Добавление языковой поддержки для инклюзивных / эксклюзивных конечных точек может быть проблематичным. Если все диапазоны включены (по выбору Ruby), разработчики соответствующим образом скорректируют конечные точки диапазона. Как вы представляете конечные точки инклюзивность или исключительность таким образом, чтобы это было визуально однозначно и однозначно с простой грамматикой синтаксического анализатора?
  • Используете ли вы диапазон для большего, чем просто повторение? Типичные примеры включают сравнения диапазонов, сращивание, сравнение значений в диапазоне. Если да, то как вы представляете эти возможности? (См. Ссылку на класс Range для идей по каждому из этих примеров.)

Кстати, диапазоны довольно хороши, если вы разрешите их включение в оператор switch, как это делает Ruby:

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

Я не говорю, что объект диапазона Ruby - это конец всего и вся, но это работающая реализация концепции, о которой вы говорите. Поиграйте с ним, чтобы увидеть, что вам нравится, что не нравится, и что вы делаете по-другому.

Берин Лорич
источник
Внимательно прочитайте вопрос, OP уже знает о диапазонах 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

Одно из решений, которое я, безусловно, рассмотрю, - это использование перегрузки операторов, чтобы, например,

1+[0..3]*5

Это не обязательно будет сразу же прозрачно для всех, но как только они остановятся и подумают, я надеюсь, что большинство программистов поймут это, и люди, которые регулярно используют язык, просто выучат его как идиому.

Чтобы уточнить, результатом будет [1, 6, 11, 16]поднятие умножения, а затем сложение по диапазону. Я не осознавал, что это может быть неоднозначным для пользователей Python; Я считаю диапазоны подмножествами общих заказов, а не списками. и повторение набора не имеет смысла.

Питер Тейлор
источник
2
Очень неоднозначно list expression * 5также может означать «повторить значение list expression5 раз», как в Python.
nikie
Это очень странно выглядит, и я не уверен, что это будет ... 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? что-то еще, возможно? В любом случае, я считаю эту запись совершенно нелогичной. Похоже, что это может быть какая-то странная операция с указателем C ...
FrustratedWithFormsDesigner