Я думал о том, как бы я занялся проектированием «идеального» литерала диапазона, если бы я занимался дизайном языка. Для вас, кто не знает, вы знаете литерал диапазона в выражении, представляющем диапазон значений, например 1-4. Они чаще всего используются в циклах for / foreach
Кажется, есть пара вопросов, которые следует учитывать
Поддержка инклюзивных и эксклюзивных диапазонов, привязка к +1 или -1 к конечным точкам кажется немного ошибочной и подверженной ошибкам.
Поддержка степпинга, так что вы можете сделать диапазон четных или нечетных чисел, например
Читаемость, должно быть очевидно, что описывает диапазон
Однозначность, должно быть совершенно однозначно то, что описывает литерал диапазона
Значение по умолчанию должно быть от включающего к исключительному, поскольку именно это используется в большинстве случаев для циклического перебора массивов и т. Д.
В любом случае, одним из примеров литерала диапазона, который я видел, является Ruby, который имеет форму 1..3 для исключительного (в конце) диапазона и 1 ... 3 для включающего (в конце). Вы также можете сделать 1..10.step (5). После тщательного рассмотрения я обнаружил, однако, пару вещей, которые мне не нравились в этом подходе (из моего ограниченного знания рубина)
Вы можете описать только включительно и эксклюзивно для конца. При описании большинства сценариев это выглядит немного противоречивым.
Варьируется просто доп. Похоже, это рецепт, из-за которого трудно понять, является ли диапазон включительным или эксклюзивным. Я не знаю о вас, но точки имеют тенденцию становиться чем-то вроде размытия :)
Добавление метода, такого как нотация для диапазонов, кажется, смешивает понятие литерала с понятием класса, который кажется немного противоречивым (даже если диапазоны компилируются в класс)
В любом случае, после обдумывания разных альтернатив. Я придумал это
- [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 для включительно-эксклюзивного было бы более логичным
1,5,10,15,20
Разрыв 4, 5, 5, 5 ?!Ответы:
Зачем изобретать то, что уже существует в математике?
Интервальная запись
Это должно охватывать ваш пункт «Однозначность», поскольку он уже существует.
Ваша единственная проблема будет определять шаг. Может быть, что-то еще в математике может помочь с этим?
источник
[1..5[
), запутает редакторов, по крайней мере, так же, как стандартные интервальные обозначения.!
для исключения первого или последнего элемента может быть хорошо.Вы видели диапазоны Haskell? Их идея для шагов похожа на вашу (в середине), но обозначена синтаксической разницей (из ответа @ luqui ):
Я считаю эту запись очень интуитивной: вы начинаете перечислять и пропускаете тело, чтобы отметить, где оно должно заканчиваться.
Это не относится к случаю «исключительного», но, честно говоря, я бы лучше однажды прояснил поведение (укажите, какая граница является включающим, а какой - исключительным) и ожидает, что пользователь внесет коррективы, если синтаксис не предельно ясен (и не смущает языковых редакторов).
источник
Вы должны прочитать о списках на языках, которые их предлагают.
Например, Python очень хорошо покрывает ваши случаи с помощью
range()
функции и понимания списка для случаев, которые слишком сложны для выраженияrange()
.источник
Я считаю, что ваша запись далеко не однозначна. Интуитивно,
[0..5..20]
мне не кажется, что диапазон с шириной шага = 5. В некоторых угловых случаях он даже не срабатывает: как насчет выражения множества (0,2)[0..2..2]
или что я должен поместить в середину?Я думаю, что нотация срезов Python - это надежный подход
[start:end:step]
(шаг необязательный).Если вам действительно нужна поддержка эксклюзивных и инклюзивных диапазонов, я бы использовал стандартную нотацию диапазонов (т. Е. Используя
(
и[
), если это не вводит синтаксические неоднозначности в вашем языке.источник
[]
,[[
,]]
и][
, не скобку ... и наш стандарт лучше, конечно;)Я думаю, что когда вы устанавливаете третье значение приращения, вам лучше добавить это конец, а не середину, поскольку это необязательное значение, и оно кажется более интуитивным для опытных программистов, чем добавление необязательного третьего аргумента в середине ,
поэтому вместо [1..5..20] вы можете сделать что-то вроде [1..20] [5] или [1..20,5]
источник
Почему бы просто не использовать [1..4], [2..5], [2..4]? Исключая диапазоны не дают большой выгоды. Вам не нужно писать MIN + 1 или MAX-1, да, но они все равно не запрещают это. Слишком много вариаций, имхо. Мой язык по выбору, scala, имеет (от 1 до 3) и (от 1 до 3) [= (от 1 до 2)], но в начале меня просто смутило. Теперь я всегда использую 'x to y' и поэтому знаю, что опция, которую я не использую, является исключающей, но, конечно, я не получаю пользу от опции, которую я не использую.
конечно (от 1 до MAX) (x => y = (MAX + 1) - x), но это значительно и не удобно для пользователя.
это, конечно (от 0 до 4) (х => у = х * 5) не так много шаблонно. Спорные.
источник
Как насчет чего-то вроде этого:
Символ «
i
и»e
во второй паре квадратных скобок указывает, является ли начало или конец диапазона включающим или исключительным (или вы можете использовать егоincl
, иexcl
если вы хотите быть более ясным).by 5
указывает интервал шаговый. Первый и последний пример включают первое и последнее значение, поэтому я пропустил[i,i]
, что, я думаю, будет нормальным поведением по умолчанию.Значения по умолчанию могут быть
[i,i]
для включающего / исключающего спецификатора иby 1
для спецификатора шага.Обычно я бы предложил стандартные обозначения с участием
(
и[
как было упомянуто @Dan McGrath, но я согласен , что в коде это может выглядеть запутанным.источник
И победителем становится
Извините за выбор собственного решения, я действительно ценю все комментарии и отзывы, и, пожалуйста, критикуйте это решение, если вы обнаружите, что с ним что-то не так.
Поэтому я решил пойти с:
Как вы можете видеть, инклюзивным является значение по умолчанию в обоих смыслах, это то, что наиболее интуитивно понятно, особенно при использовании степпинга. Ты можешь использовать ! сделать конец эксклюзивным.
Недостатком является то, что обычно вы хотите использовать исключение при работе с массивом, но, опять же, в большинстве случаев вам, вероятно, следует использовать что-то вроде for-each в этих случаях. Если вам действительно нужно работать с индексом, парсер может распознать, когда вы, возможно, забыли маркер исключения в конце, и выдать предупреждение
Я пошел с использованием .. с обеих сторон переменной шага вместо запятой или чего-то еще, потому что это выглядело наиболее чисто, и я надеюсь, что это наиболее читабельно.
Я также добавил синтаксис с запятыми, чтобы иметь возможность создавать диапазоны, где разные части имеют разные шаги
источник
Я бы не стал использовать форму «[1..5 [» по одной и той же причине, по которой вы избегали бы смешивать скобки и скобки - это может привести к путанице в скобках большинства существующих редакторов. Возможно, используйте маркер внутри фигурных скобок, например «[1 .. | 5]».
Другая вещь, которую следует учитывать, - это поведение методов, чтобы получить пределы. Например, «начало» / «конец» против «первый» / «последний» против «мин» / «макс». Они должны быть нормальными как для инклюзивных, так и для эксклюзивных ограничений, а также для тех, у кого размер шага.
источник
У Ruby есть нотация и объект Range, который работает. По сути это выглядит так:
В Ruby размер шага не является функцией диапазона, а скорее функцией итерации по диапазону. Мы могли бы использовать тот же диапазон выше и проходить по нему по-разному, если бы мы хотели:
Итак, вот что вы можете рассмотреть:
Кстати, диапазоны довольно хороши, если вы разрешите их включение в оператор switch, как это делает Ruby:
Я не говорю, что объект диапазона 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).
Одно из решений, которое я, безусловно, рассмотрю, - это использование перегрузки операторов, чтобы, например,
Это не обязательно будет сразу же прозрачно для всех, но как только они остановятся и подумают, я надеюсь, что большинство программистов поймут это, и люди, которые регулярно используют язык, просто выучат его как идиому.
Чтобы уточнить, результатом будет
[1, 6, 11, 16]
поднятие умножения, а затем сложение по диапазону. Я не осознавал, что это может быть неоднозначным для пользователей Python; Я считаю диапазоны подмножествами общих заказов, а не списками. и повторение набора не имеет смысла.источник
list expression * 5
также может означать «повторить значениеlist expression
5 раз», как в Python.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 ...