VladD2 wrote:
> Хочется услышать мнение народа о том как бы он хотел видеть паттерн > перебора значений из некоторого диапазона. > > Например, в С/С++ для этого используется императивный стиль: > > for (int i = 0; i < len; i++) > > > но этот синтаксис слишком громоздок и может приводить к случайным > ошибкам (так как императивен). > > Во многих ЯП можно увидить синтаксис вроде: > > foreach (i in 0..3) // выдает последовательность 0, 1, 2, 3
Честно говоря, С++ синтаксис мне больше всего нравится, т.к. более гибок, позволяет перебирать не только целые числа в
некоем интервале с шагом 1, но фактически что угодно и как угодно. А простой перебор чисел от A до B на практике редко
встречается (по крайней мере в моей практике). Я обычно перебираю коллекции, родительские элементы, рекордсеты, и
прочее, числа встречаются довольно редко.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
VD>но этот синтаксис слишком громоздок и может приводить к случайным ошибкам (так как императивен).
Я тебя ещё больше напугаю В си++ пишут так
for (int i = 0; i < len; ++i)
VD>В общем, приветствуются любые мысли.
Как показывает практика идея о том что элемент обозначающий конец это следующий после последнего — очень здравая. В твоём контексте
foreach (int i in 0..3) выдаёт 0 1 2
foreach (int i in 0..array.Length) перебирает все элементы массива
либо
foreach (int i in 0 to 3) выдаёт 0 1 2
foreach (int i in 0 to array.Length) перебирает все элементы массива
либо
foreach (int i in 0 upto 3) выдаёт 0 1 2
foreach (int i in 0 downto 3) выдаёт 2 1 0 мелочь, а приятно
foreach (int i in 0 upto array.Length) перебирает все элементы массива
foreach (int i in 0 downto array.Length) перебирает все элементы массива в обратном порядке
причём foreach (int i in 0 upto 3) и foreach (int i in 3 downto 0) равнозначны
Здравствуйте, kan_izh, Вы писали:
_>Честно говоря, С++ синтаксис мне больше всего нравится, т.к. более гибок, позволяет перебирать не только целые числа в некоем интервале с шагом 1, но фактически что угодно и как угодно.
Понимаш ли в чем дело? С-шный for никто не отменяет. Но его гибкость выливается в ошибки и усложнение чтения кода когда он используется для простых вещей.
Мы (люди) думаем абстракциями. Когда ты пишешь:
for (int i = 0; i < array.Length; i++)
array[i] = f(array[i]);
ты реально думашь не так:
1. Объявить перменную целого типа.
2. Инициализировать ее нулем который является нижней границей массива.
3. Выполнять условие цикла пока переменная не превысит значения длинны массива.
4. На каждой итерации увеличить индекс на один.
5. Вынуть значение по индексу находящемуся в ячейке с номером заданным в переменной i.
6. Применить к значению функцию f().
7. Поместить значение преобразования по индексу находящемуся в ячейке с номером заданным в переменной i.
Ведь если так мыслить, то даже самая приметивная программа станет архи-сложной.
По этому за конструкцией "for (int i = 0; i < array.Length; i++)" ты улавливашь некий паттерн. В данном случае "перебрать все индексы массива array". Но этот паттерн тебе приходится угадывать. А тут есть две проблемы. 1. Ты можешь не врено принять за этот паттерн просто похожую конструкцию, например, "for (int i = 0; i <= array.Length; i++)" или "for (int i = 0; i < array.Length; i--)". 2. Разглядывать паттерны в накромождениях кода очень не просто.
Посему код написанный в таком стиле плохо читается.
Чем более внятно будет выражен паттерн, тем проще будет читать код, и тем сложнее будет ошибиться в его написании или понимании. Сравни приведенный выше фракмент с:
foraech (i in IndexesOf(array))
array[i] = f(array[i]);
или темболее с:
ConvertElements(array, f);
_> А простой перебор чисел от A до B на практике редко встречается (по крайней мере в моей практике).
Тогд посчитай сколько у тебя в программе встречается вот таких вот for-ов. Думаю — уйма.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Нет разницы писать i++ или ++i если возвращаемое значение выражения не используется. Так что пишут так как больше нравится. Я лично предпочитаю i++.
A>Как показывает практика идея о том что элемент обозначающий конец это следующий после последнего — очень здравая. В твоём контексте
A>
A>foreach (int i in 0..3) выдаёт 0 1 2
A>foreach (int i in 0..array.Length) перебирает все элементы массива
A>foreach (int i in 0 to 3) выдаёт 0 1 2
A>foreach (int i in 0 to array.Length) перебирает все элементы массива
A>
Общепринято, что запись "0..3" и "i to 3" возвращает последовательность включающую 3 (т.е. 1, 2, 3).
Менять семантику означает повергать кучу народа на мучения.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона. VD>В общем, приветствуются любые мысли.
Щас ересь скажу
Почему бы не использовать традиционную математическую нотацию для inclusive/exclusive:
foreach(i in [0,3]) // 0,1,2,3
foreach(i in [0,3[) // 0,1,2
foreach(i in ]0,3]) // 1,2,3
foreach(i in ]0,3[) // 1,2
Только вот непосредственно "[]" уже заняты и будут конфликтовать, следовательно надо придумать какие-нибудь другие "крокозяблы". Но это может все испортить.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, VladD2, Вы писали:
VD>Нет разницы писать i++ или ++i если возвращаемое значение выражения не используется.
Разница естьв скорости. Для int всё равно, а вообще говоря i++ медленее.
VD>Общепринято, что запись "0..3" и "i to 3" возвращает последовательность включающую 3 (т.е. 1, 2, 3). VD>Менять семантику означает повергать кучу народа на мучения.
Где это общепринято? Запись с двумя точками я помню только в паскале, но для меня это "дела давно минувших дней, преданья старины глубокой"
Поверь, к удобной вещи, пусть даже и новой, люди привыкают быстро.
Здравствуйте, VladD2, Вы писали:
VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона. VD>В общем, приветствуются любые мысли.
foreach (x in array)
{
}
foreach (i in [0, array.Length); ++i) // i = 0..(array.Length-1)
{
}
foreach (i in [1, array.Length]; ++i) // i = 1..array.Length
{
}
foreach (0 <= i < array.Length; ++i) // i = 0..(array.Length-1)
{
}
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, McSeem2, Вы писали:
MS>>Щас ересь скажу MS>>Почему бы не использовать традиционную математическую нотацию для inclusive/exclusive:
A>Я об этом подумал, но фигня выходит A>(0..3) A>[0..3) A>(0..3] A>[0..3] A>в глазах рябит
Здравствуйте, VladD2, Вы писали:
VD>Мы (люди) думаем абстракциями.
+1. Похоже, что именно поэтому так быстро прижился foreach в C#, гораздо чаще используется for в C++ по сравнению с while и в очень редких случаях применяется do while.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, c-smile, Вы писали:
CS>Парсить такое трудно если не невозможно вообще.
В Nemerle действительно невозможно. Он контролирует парность скобок еще до синтаксического анализа. Это позволяет встравивать в язык синтаксические расширения и DSL-и.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VladD2,
VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона.
VD>В общем, приветствуются любые мысли.
Хм. Будет немного непривычно:
12.times { say 'hello' } // _1 принимает значения от 0 до 11
(2..16).times { say 'hello '_1 } // _1 принимает значения от 2 до 16
(10+.5).times { say 'hello '_1 } // _1 принимает значения от 5 до 14 (то есть 10 различных значений)
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Хм. Будет немного непривычно: LCR>
LCR>12.times { say 'hello' } // _1 принимает значения от 0 до 11
LCR>(2..16).times { say 'hello '_1 } // _1 принимает значения от 2 до 16
LCR>(10+.5).times { say 'hello '_1 } // _1 принимает значения от 5 до 14 (то есть 10 различных значений)
LCR>
(2..16) (x) { say 'hello 'x } // _1 принимает значения от 2 до 16
(10+.5) (y) { say 'hello 'y } // _1 принимает значения от 5 до 14 (то есть 10 различных значений)
?
Т.е. фактически задание диапазона параметра вызываемого метода.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
IT>(2..16) (x) { say 'hello 'x } // _1 принимает значения от 2 до 16
IT>(10+.5) (y) { say 'hello 'y } // _1 принимает значения от 5 до 14 (то есть 10 различных значений)
?
Ну можно и так. Могу ещё предложить задавать диапазон в гварде:
(x, y)~(#10, 0..9): {say 'hello 'x','y}
Однако по-прежнему тот вариант с i.10 мне нравится больше.
IT>Т.е. фактически задание диапазона параметра вызываемого метода.
Да. Хотя вот здесь
LCR>>12.times { say 'hello' } // _1 принимает значения от 0 до 11
aCollection do: [ :element | "do something with element" ].
примеры:
aCollection do: [ :element | element blink ].
Посылает каждому элементу коллекции aCollection сообщение blink.
aCollection do: [ :element | anObject doSomethingWith: element ].
Посылает объекту anObject сообщение doSomethingWith: на каждый элемент коллекции aCollection. Параметром каждый раз передаётся текущий элемент коллекции.
Перебор по числам (реально требуется довольно редко):
общий вид:
aNumber1 to: aNumber2 do: [ :number | "do something with number" ].
или
(aNumber1 to: aNumber2) do: [ :number | "do something with number" ].
(с точки зрения поведения разницы нет)
пример:
1 to: 10 do: [ :i | anObject doSomethingWith: i ].
Перебор по числам с интервалом:
общий вид:
aNumber1 to: aNumber2 by: aNumber3 do: [ :number | "do something with number" ].
или
(aNumber1 to: aNumber2 by: aNumber3) do: [ :number | "do something with number" ].
(с точки зрения поведения разницы нет)
примеры:
1 to: 10 by: 3 do: [ :i | anObject doSomethingWith: i ].
Здравствуйте, IT, Вы писали:
IT>+1. Похоже, что именно поэтому так быстро прижился foreach в C#, гораздо чаще используется for в C++ по сравнению с while и в очень редких случаях применяется do while.
do while применяется так редко не поэтому, а потому что ситуации, когда необходимо выполнить тело цикла один раз обязательно, встречаются намного реже, чем ситуации, когда это не требуется.
for используеться чаще, чем while просто потому, что с for мы обычно ассоциируем последовательный перебор (0,1,2..) , а c while — произвольный итерационный процесс. Хотя это и неверно, но мы так подсознательно считаем. Есть у нас такие абстракции — for и while. А последовательный перебор встречается чаще.
Здравствуйте, VladD2, Вы писали:
VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона.
Да.. Есть еще проблемы на свете...
А проще всего было в Фортране
DO 100 I = 1,10
или с шагом
DO 100 I = 1,11,2
Только вот никому не советовали по ошибке вместо запятой ставить точку. Из-за этой точки в 60-е годы одна американская ракета при взлете самоуничтожилась (по крайней мере так говорят)
public class Range : IEnumerable<int>
{
private int _low;
private int _high;
public IEnumerator<int> GetEnumerator()
{
for (int i = _low; i <= _high; i++)
yield return i;
}
#region Construction
public Range(int low, int high)
{
_low = low;
_high = high;
}
public static Range Indexes<T>(T[] array)
{
return new Range(0, array.Length - 1);
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
использование:
int[] a = new int[5];
foreach(int i in Range.Indexes(a)) // нет выбора между Length/Length-1
Console.Write(i);
foreach(int i in new Range(0, 10))
Console.Write(i);
Предполагается набор перегруженных конструкторов для указания step. Предполагается наличие свойства Reverse для обращения обхода. Предполагается наличие операций пересечения/объединения интервалов. Велком
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, VladD2, Вы писали: VD>>В общем, приветствуются любые мысли. S>Мысль такая:
<skipped>
М-да... Похоже, пора объявить конкурс на самую длинную реализацию цикла for...
Господа, а не кажется ли Вам, что для того, чтобы сравнивать нынешний программный продукт по числу LOC c тем, что писали 10 лет назад, надо для нынешнего продукта автоматически применять понижающий коэффициент, равный так примерно 10 ?
P.S. А вообще дискуссия начинает понемногу напоминать незавбвенную "Hello, World".
Если использовать foreach, то надо подразумевать, что x итерирует по множеству, соответственно запись множества при использовании оператора цикла и при самостоятельном использовании должна быть одинакова, Ruby — как раз тому пример.
Если же мы просто определяем границы и правила итерации (шаг и выход за границы), то ИМХО, оператор for предпочтительней.
Это по самому ключевому слову было.
Далее.
Для первого случая, ИМХО, надо придумать операторы порождения потока, результат применения которых неплохо смотрелся бы как IEnumerator<> или IEnumerable<>.
Почему бы не взять "знакомые" конструкции с других языков (ruby, pascal)?
[1 .. 3] // от 1-го до 3-х включительно
[1 .. 10; 2] // шаг 2
[0 .. 10, 20 .. 30; 5] = {0, 5, 10, 20, 25, 30}
public delegate T NextIndexGenerator<T>(T current); // позволить использовать формулу для вычисления следующего члена ряда
// исходя из значения предыдущего
[1 .. 1024; @current*2] = {1, 2, 4, 8, ..., 1024}
[0.1 .. 0.9, Math.Sqrt] = {0.1, 0.316, ..., 0.8999 } // ряд, сходящщийся к 1.0 по формуле next = sqrt(current);
Несчет неудобства array.Length-1 ничего сказать не могу, лично мне безразлично. Если кому-то важно, то можно оппробовать разные формы записи для открытых и закрытых диапазонов. Я бы предложил так:
[0..array.Length),
но боюсь, случайная опечатка в парных скобочках будет пересекаться с семантикой, что не есть гут. Может быть будут еще идеи как указать открытый диапазон? А может быть ввести некое ключевое слово, типа before:
[1 .. before 1024; @current*4]
----------
Насчет же указания границ перебора для цикла for — все предложенные варианты интересны (хоть и записаны были как foreach). Действительно, надо взять несколько наиболее встречающихся случаев переборав цикла и заточить синтаксис под них.
Вот еще варианты:
for(i from 0 to 10 step 2) // закрытый диапазон слева и справаfor(i from 0 before 10 step 5) // открытый диапазон
Кстати, почему бы не сделать from 0 по умолчанию для before (самый востребованный сценарий использования)?
Совсем коротко выходит:
int[] arr = new int[10];
for(i before arr.Length)
arr[i]=i*i;
Здравствуйте, VladD2, Вы писали:
VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона.
VD>foreach (i in 0..3) // выдает последовательность 0, 1, 2, 3 VD>этот синтаксис хорош, но неудобен когда нужно перебрать значения индекса некой коллекции: VD>foreach (i in 0..array.Length — 1) // не нравится этот "- 1"
Есть такие мысли:
1. Использовать генератор xrange() (или range()) для открытых справа диапазонов. При этом ".." будет соответствовать закрытому интервалу, вроде closed_range()
2. for (int i = 0 while i < 10), for (int i = 0 while i <= 10 step 2). Но мне очень не нравится, что < можно спутать с <=, по сути это тот же Си-шный for.
3. Для перебора индексов использовать какой-нибудь генератор вроде IndexesOf из твоего примера и этим ограничиться.
4. Финт: for (int i = 0 to 10) для открытого сверху (0..9), for (int i = 1 upto 10) для закрытого (1..10). Перепутать трудно, визуально длина слов разная. Но с первого взгляда кажется непривычным. Собственно, сами слова "to" и "upto" можно исопльзовать вместо двух и трех точек для конструирования интервалов, не только в конструкции for.
Pavel Dvorkin,
PD>Господа, а не кажется ли Вам, что для того, чтобы сравнивать нынешний программный продукт по числу LOC c тем, что писали 10 лет назад, надо для нынешнего продукта автоматически применять понижающий коэффициент, равный так примерно 10 ?
Чаще всего величина библиотечного кода нас не волнует. Можно хоть на 1024 умножить, главное чтобы потом в своём файле иметь возможность писать
(+/ % #) list
вместо
int n = list.size();
double sum = 0;
for (int i = 0; i < n; i++)
sum += list[i];
return sum/n;
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Чаще всего величина библиотечного кода нас не волнует. Можно хоть на 1024 умножить, главное чтобы потом в своём файле иметь возможность писать LCR>(+/ % #) list
LCR>вместо LCR>int n = list.size(); LCR>double sum = 0; LCR>for (int i = 0; i < n; i++) LCR> sum += list[i]; LCR>return sum/n;
Отличная иллюстрация двух диких крайностей
Я предпочитаю золотую середину:
sum = reduce(float.__add__, list, 0.0)
В других языках reduce имеет имя fold или accumulate.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
Кё>>Я предпочитаю золотую середину: Кё>>sum = reduce(float.__add__, list, 0.0) LCR>Я так полагаю, это Питончик? Да, там кстати считалось среднее
Ну а насчет среднего — не намного сложнее, return reduce(float.__add__, lisT, 0.0)/len(lisT)
Кстати, а как в Nemerle сослаться на оператор + для класса, например, для целых? Пробовал System.Int32.op_Add и System.Int32.operator+, в документации не знаю где искать.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>do while применяется так редко не поэтому, а потому что ситуации, когда необходимо выполнить тело цикла один раз обязательно, встречаются намного реже, чем ситуации, когда это не требуется.
Это зависит от того, как мыслит человек. Например, у меня большая часть циклов вообще полуторные: одна часть цикла должна выполняться на одну итерацию больше, чем другая. А чистые do и while, как вырожденные случаи, встречаются реже.
VD>Понимаш ли в чем дело? С-шный for никто не отменяет. Но его гибкость выливается в ошибки и усложнение чтения кода когда он используется для простых вещей.
VD>Ведь если так мыслить, то даже самая приметивная программа станет архи-сложной.
VD>По этому за конструкцией "for (int i = 0; i < array.Length; i++)" ты улавливашь некий паттерн. В данном случае "перебрать все индексы массива array". Но этот паттерн тебе приходится угадывать. А тут есть две проблемы. 1. Ты можешь не врено принять за этот паттерн просто похожую конструкцию, например, "for (int i = 0; i <= array.Length; i++)" или "for (int i = 0; i < array.Length; i--)". 2. Разглядывать паттерны в накромождениях кода очень не просто.
VD>Посему код написанный в таком стиле плохо читается.
Эта сложность служит барьером от случайных людей. Можно избавить программистов от проблем на этом, весьма низком уровне. Однако, если человек не может научиться преодолевать подобные препядствия, то польза от него, как программиста, довольно сомнительна. Оперирование паттернами более высокого уровня, в действительности, намного сложнее. Если, конечно, речь не идёт о "Copy" и "Paste" фрагментов кода из документации и др. источников.
Здравствуйте, vdimas, Вы писали: V>Несчет неудобства array.Length-1 ничего сказать не могу, лично мне безразлично. Если кому-то важно, то можно оппробовать разные формы записи для открытых и закрытых диапазонов. Я бы предложил так: V>
[0..array.Length),
Поскольку итерация в массиве — очень частая штука, имеет смысл сделать ее отдельной операцией. В дотнете уже придумано отличное решение — в большинстве случаев мне совсем не надо париться с индексом благодаря встроенному foreach:
int[] a = new int[] {1, 2, 3, 4};
int sum = 0;
foreach(int item in a)
sum += item;
В тех редких случаях, когда мне все же нужен именно индекс, я бы предпочел вообще отказаться от манипуляций с Length. Оптимально было бы так:
int[] a = new int[] {1, 2, 3, 4};
int weightedSum = 0;
foreach(int i in a.Indexes)
weightedSum += i*a[i];
V>но боюсь, случайная опечатка в парных скобочках будет пересекаться с семантикой, что не есть гут. Может быть будут еще идеи как указать открытый диапазон? А может быть ввести некое ключевое слово, типа before:
Мне кажется, сама проблема использования диапазонов в значительной мере надумана. Во-первых, диапазон настолько часто приделан к коллекции, что проще сделать нарошные операции извлечения диапазона напрямую, чем давать человеку возможность ошибиться при "двухстадийной" схеме — сначала вытаскиваем границы, а потом формируем из них диапазон.
Во-вторых, все эти скобочки экономят буквально одиночные символы, в ущерб понятности и безошибочности. По мне, так гораздо лучше ввести необходимые функции-конструкторы диапазонов:
Range(low, high) // для (1, 4) переберет 1, 2, 3, 4
ExclusiveRange(beforeLow, afterHigh) // для (1, 4) переберет (2, 3)
Since(low) // для (1) будет перебирать 1, 2, 3, ... до бесконечности
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, VladD2, Вы писали:
VD>этот синтаксис хорош, но неудобен когда нужно перебрать значения индекса некой коллекции: VD>
VD>foreach (i in 0..array.Length - 1) // не нравится этот "- 1"
VD>
Для полноты картины:
for I := Low(A) to High(A) do;
Я для своих классов в которых нумерация начинается с нуля, ввожу еще одно поле Limit = Length — 1. В этом случае цикл:
for I := 0 to A.Limit do;
Хорошая реализация в MATLAB. Там цикл имеет вид
for i = A
...
end
где i это переменная, а A это массив (рассматривается как одномерный). Поскольку массивы можно определить при помощи оператора ":", то Цикл от 1 до 10 может быть записан как
for i = 1:10
...
end
Цикл от 10 до 1 дожет быть записан как
for i = 1:10:-1
...
end
Распечатать все элементы массива можно просто
for i = A
print(i)
end
Если при этом добавить для классов свойство Range, то получим
Здравствуйте, VladD2, Вы писали:
VD>Мне в голову прили следующие варианты: VD>
VD>foreach (x where 0 >= x < 10 step 1) // "step 1" необязательный параметр позволяющий задать шаг отличный от еденицы
VD>
И чем это лучше кода for (x = 0; x < 10; ++x)?
Почему так широко используется foreach? Потому что полностью соответствует задаче — "последовательно получить элементы коллекции". For задаче не соответствует, т.к. задача требует получения элементов, а не индексов и не содержит ни условия для отбора индексов, ни шага изменения индекса.
Ты же рассматриваешь другую задачу, а именно — "получить индексы в диапазоне от 0 до 10 с шагом 1". В чем здесь заключается несоответсвие for'а задаче? For работает именно с индексами, в нем задается диапазон и шаг, задавать еще что-то не надо. For для такой задачи по меньшей мере не хуже любой другой формы записи, соответственно не понятно стремление к его замене и тем более замене дублирующей.
Здравствуйте, Кодёнок, Вы писали:
Кё>Кстати, а как в Nemerle сослаться на оператор + для класса, например, для целых? Пробовал System.Int32.op_Add и System.Int32.operator+, в документации не знаю где искать.
Должно быть Int32.op_Addition. По крайней мере компилиться, но во время выполнения падает, видимо баг (может уже поправили).
Здравствуйте, Кодёнок, Вы писали:
Кё>Кстати, а как в Nemerle сослаться на оператор + для класса, например, для целых? Пробовал System.Int32.op_Add и System.Int32.operator+, в документации не знаю где искать.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Хм. Будет немного непривычно: LCR>
LCR>12.times { say 'hello' } // _1 принимает значения от 0 до 11
LCR>(2..16).times { say 'hello '_1 } // _1 принимает значения от 2 до 16
LCR>(10+.5).times { say 'hello '_1 } // _1 принимает значения от 5 до 14 (то есть 10 различных значений)
LCR>
Здравствуйте, VladD2, Вы писали:
VD>В Руби для таких случаев используется синтаксис: VD>
VD>foreach (i in 0...3) // то есть добавляется третья точка.
VD>
VD>Но это не интуитивно и легко путается с вариантом с двумя точками.
Это ты где в Ruby цикл foreach нашел?
В Ruby есть понятие Range, которое записывается либо с двумя точками (тогда это соответствует [a,b]), либо с тремя точками (что соответствует [a,b)).
Кроме того, если нужно перебрать все элементы контейнера, то используются методы each:
[1, 2, 3, 4].each { |item| ... }
Если нужно выполнить определенное количество циклов, то используется метод times:
10.times { |n| ... }
Если нужно перебрать значения от a до b, то можно использовать методы upto, downto или Range#each:
1.upto(10) { ... } # от 1 до 10.
10.downto(1) { ... } # от 10 до 1.
(1..10).each { ... } # от 1 до 10.
(1...10).each { ... } # от 1 до 9
Цикла foreach в Ruby нет. Есть for in, для которого важно, чтобы в итерируемом объекте был метод each:
Вы можете использовать for для итерации по любому объекту, который отвечает на метод each, например Array или Range:
for i in ['fee', 'fi', 'fo', 'fum']
print i, " "end
for i in 1..3
print i, " "end
for i in File.open("ordinal").find_all { |l| l =~ /d$/}
print i.chomp, " "end
выводит:
fee fi fo fum 1 2 3 second third
Как только ваш класс определяет соответствующий метод each, вы можете использовать цикл for для его обхода
class Periods
def each
yield"Classical"yield"Jazz"yield"Rock"end
end
periods = Periods.new
for genre in periods
print genre, " "end
VladD2 wrote:
> _>Честно говоря, С++ синтаксис мне больше всего нравится, т.к. более > гибок, позволяет перебирать не только целые числа в некоем интервале с > шагом 1, но фактически что угодно и как угодно. > > Понимаш ли в чем дело? С-шный for никто не отменяет. Но его гибкость > выливается в ошибки и усложнение чтения кода когда он используется для > простых вещей. > > Мы (люди) думаем абстракциями. Когда ты пишешь: > > for (int i = 0; i < array.Length; i++) > array[i] = f(array[i]); > > > ты реально думашь не так: > 1. Объявить перменную целого типа. > 2. Инициализировать ее нулем который является нижней границей массива. > 3. Выполнять условие цикла пока переменная не превысит значения длинны > массива. > 4. На каждой итерации увеличить индекс на один. > 5. Вынуть значение по индексу находящемуся в ячейке с номером заданным в > переменной i. > 6. Применить к значению функцию f(). > 7. Поместить значение преобразования по индексу находящемуся в ячейке с > номером заданным в переменной i.
Нет, конечно. Просто рассматривается цикл как конструкция из 3 частей — начальное условие; условие окончания; операция
получения следующего элемента.
И не важно, что перебирается — индексы, родители, или диапозон, или ещё что...
Мне нравится единообразие при многообразии
for(int i=0; i<arguments.length; i+=2)
{
map[arguments[i]] = arguments[i+1];
}
for(Node *parent = theNode; parent; parent = parent->getParent())
{
}
for(Range r(collection); r; ++r)
{
cout << *r;
}
char *list[] = {"aaa", "bbb", "ccc", NULL};
for(char **elem = list; *elem; ++elem)
{
}
//Синтаксис типа этого будет совершенно не в тему. А преимущества какие?
foreach( int i=[0..arguments.length) )
{
cout << arguments[i];
}
// Ещё можно оправдать такой синтаксис, тем, что выкидывается неиспользуемое здесь понятие "индекс"/"итератор",
используется только "коллекция" и её "элемент коллекции".
foreach int arg(arguments)
{
cout << arg;
}
В этом и заключается абстракция — в совершенно на первый взгляд различных конструкциях увидеть одинаковую сущность. А
придумывание красивого синтаксиса для какого-то частного случая — это процесс обратный абстрагированию, это
синтаксический сахар. Да, сложными абстракциями сложно пользоваться новичку, но это проходит.
Резюме. В перле приняли правильное решение — перебор элементов массива (без итераторов) foreach и универсальный сишный for.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, VladD2, Вы писали:
VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона.
VD>Например, в С/С++ для этого используется императивный стиль: VD>
VD>for (int i = 0; i < len; i++)
VD>
VD>но этот синтаксис слишком громоздок и может приводить к случайным ошибкам (так как императивен).
VD>Во многих ЯП можно увидить синтаксис вроде: VD>
VD>foreach (i in 0..3) // выдает последовательность 0, 1, 2, 3
VD>
VD>этот синтаксис хорош, но неудобен когда нужно перебрать значения индекса некой коллекции: VD>
VD>foreach (i in 0..array.Length - 1) // не нравится этот "- 1"
VD>
Мне кажется, тут должно быть два паттерна: паттерн диапазона и паттерн перебора. Перебор применим как к диапазонам, так и к контейнерам. А диапазон можно использовать отдельно от перебора. Например создать контейнер, содержащий диапазоны.
Согласен, foreach (0 <= i < 3) выглядит естественнее чем foreach (i in 0 ..< 3), но во-первых я предложил, как с минимальными изменениями снять конкретные нарекания вызванные конкретной конструкцией, а во-вторых кто-то возможно найдет, что
foreach (i in offset + delta * (m..n))
более понятен нежели
foreach (offset + delta * m <= i <= offset + delta * n)
VD>foreach (i in 0..array.Length - 1) // не нравится этот "- 1"
VD>
-- Haskell
-- так:
take array.Length [0..]
-- или так:
[i | i <- [0..], i < array.Length]
VD>Вопрос в том как должен выглядить идеальный синтаксис перебора значений из диапазона на ваш взгляд.
Как в Python,Haskell etc. — совокупность генераторов и гардов, другими словами: List comprehension.
Здравствуйте, last_hardcoder, Вы писали:
_>Мне кажется, тут должно быть два паттерна: паттерн диапазона и паттерн перебора. Перебор применим как к диапазонам, так и к контейнерам. А диапазон можно использовать отдельно от перебора. Например создать контейнер, содержащий диапазоны.
Кстати. Вот в St есть #do: (типа foreach) и select: (фильрация коллекции). Наблюдательные программисты подметили, что иногда встречается патерн
типа (коллекция select: [ ...условие... ]) do: [ ...действие...]. То есть выбираем подмножество и его обрабатываем. Результат появление внутреннего итератора с фильтром типа коллекция select: [ ...условие... ] do: [ ...действие...]. От предідущего єтот вариант отличается не только отсутсвием кругліх скобок, но и отсутсвием промежуточной временной коллекции.
Что касается диапазона вообще (класс Interval в ST), то я видел, что бы он применялся только на низком уровне, при реализации самих методов do:, select: и пр.
Что касается исходного примера:
foreach (i in 0..array.Length - 1) // не нравится этот "- 1"
то в ST являются нормальным явлением методы коллекций first, last, allButFirst, allButLast, copyWithouFirst, copyWithouLast. Названия, вроде, говорят сами за себя.
Здравствуйте, Sinclair, Вы писали:
S>Мысль такая:
...
S>Предполагается набор перегруженных конструкторов для указания step. Предполагается наличие свойства Reverse для обращения обхода. Предполагается наличие операций пересечения/объединения интервалов. Велком
Сысль зравая и я даже дошел до ее аналога. Только уже в новом формате. Можно написать простенокий макрос который будет определять тип коллекции и формировать включающий дипазон (ее я озвучил здесь).
macro IndexesOf(collection)
{
// In real code one needs to do check type of collection and make specialized code
<[ $$[0..collection.Length - 1] ]>
}
...
foreach (i in IndexesOf(myArray))
...
Более того товарищь Москаль сказал, что в Немерле в ближайшее время появятся расширяющие методы и расширяющие макросы. Это позволит писать так:
foreach (i in myarr.Indexes)
...
Причем реально код будет переписываться в тот самый for.
Так что ваша улыбочка, сэр, в конце сообщения ниуместна!
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, z00n, Вы писали:
Z>Как в Python,Haskell etc. — совокупность генераторов и гардов, другими словами: List comprehension.
List comprehension перебор для такого случая. В общем-то диапазон и является простым случаем List comprehension, но все же городить нагромождения по этому поводу наверно не стоит.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, eao197, Вы писали:
E>>>5.times { |i| puts "- #{i} -" }
E>Кстати, если само значение счетчика не интересует, то можно писать просто: E>
E>5.times { puts "---" }
E>
Прикольно. Во-первых, в ST этот метод никогда не передаёт значение счетчика и для того, что бы его получить приходится писать 1 to: 5 do: [...]. Не то чтобы я этим часто пользовался, но когда изредка пишу какие-то тестики, то постоянно об этом забываю. Во-вторых, только сейчас заметил, что название метода в ST слегка неконсистентно — timesRepeat:. Почему Repeat если можно было сделать просто times:, или timesDo: на крайняк. История, блин.
Здравствуйте, VladD2, Вы писали:
VD>В Руби есть задание диапазонов с тремя точками (0...3). Об этом и шала речь. VD>Тебе же снова хочется обсудить вопрос не имеющий отношения к делу.
Я хотел сказать, что в Ruby нет оператора foreach.
А так же то, что приведенная тобой для Ruby запись:
foreach (i in 0...3)
не соответствует примеру для других языков:
foreach (i in 0..3) // выдает последовательность 0, 1, 2, 3
Поскольку для Ruby будет выдана последовательность 0, 1, 2 (без тройки). Т.е. твои два примера не эквивалентны.
Если же ты хочешь именно 0,1,2,3, то следует писать диапазон именно с двумя точками.
Так что я не пытаюсь увести разговор в сторону. а исправляю фактические ошибки. Относись к ним как опечаткам, которые заметил читатель.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Вместо того чтобы вводить в язык дополнительно три операции образования интервалов ..<, <.. и <..<, можно ввести постфиксные и префиксные унарные операции < и > (последнюю — для симметрии, как впрочем и в случае операций образования интервалов для симметрии следовало бы добавить также ..>, >.. и >..>).
Выражения <n и n> были бы сокращением для n-1, а >n и n< — для n+1.
Может быть тогда наши foreach-и логичнее было бы записать с пробелом между .. и <:
Здравствуйте, Sinclair, Вы писали:
S> В тех редких случаях, когда мне все же нужен именно индекс, я бы предпочел вообще отказаться от манипуляций с Length. Оптимально было бы так: S>
S>int[] a = new int[] {1, 2, 3, 4};
S>int weightedSum = 0;
S>foreach(int i in a.Indexes)
S> weightedSum += i*a[i];
S>
#как-то так, да
weightedSum = 0
a.each_with_index {|obj, i| weightedSum += i * obj}
Здравствуйте, eao197, Вы писали:
E>Так что я не пытаюсь увести разговор в сторону. а исправляю фактические ошибки. Относись к ним как опечаткам, которые заметил читатель.
Нда. Исправляй дальше. Общаться с тобой по существу невозможно.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона.
А зачем тебе это?
Я вот нетак давно заморачивался вопросом что некоторые куски кода приходится повторять заново.
куски небольшие — как правило пару строк или что твой паттерн перебора.
Кто-то думает что решить эту проблему можно препроцессором (R#) или шаблонами (boost).
А мне кажется, что тут помогут Code-snippetы, жаль что для с++ их ещё не сделали.
Плюсы от их применения огромны.
1) стандартизация кода через шаблонные решения.
2) скорость чтения кода от применения узнаваемых решений.
3) автоматическая переконвертация кода под другой стиль.
Короче через 5 лет программер будет писать в своём коде паттерн в полюбившемся ему виде,
а при сдаче проекта другому программеру или заказчику маленькая программка переправит всё в соответствии со вкусами заказчика.
Здравствуйте, Sinclair, Вы писали:
S> В тех редких случаях, когда мне все же нужен именно индекс, я бы предпочел вообще отказаться от манипуляций с Length. Оптимально было бы так: S>
S>int[] a = new int[] {1, 2, 3, 4};
S>int weightedSum = 0;
S>foreach(int i in a.Indexes)
S> weightedSum += i*a[i];
S>
+1 за общую мысль, но мне не нравится реализация.
Один из частых случаев, когда нас интеерсует именно индекс — это заполнение значениями value-type массива.
Например:
struct SomeStruct {
public double a, b, c, d, e, f;
}
...
SomeStruct[] s = new SomeStruct[100];
for(int i = 0; i<s.Length; i++)
Fill(s[i]);
...
public void Fill(ref SomeStruct item) {}
Так вот, избавление от явного указания границ могло бы выглядеть так:
foreach(ref item in s)
Fill(item);
Красота!
S>Мне кажется, сама проблема использования диапазонов в значительной мере надумана. Во-первых, диапазон настолько часто приделан к коллекции, что проще сделать нарошные операции извлечения диапазона напрямую, чем давать человеку возможность ошибиться при "двухстадийной" схеме — сначала вытаскиваем границы, а потом формируем из них диапазон.
Угу, но все же лучше обойтись вообще без явных вытаскиваний диапазонов.
S>Во-вторых, все эти скобочки экономят буквально одиночные символы, в ущерб понятности и безошибочности. По мне, так гораздо лучше ввести необходимые функции-конструкторы диапазонов: S>Range(low, high) // для (1, 4) переберет 1, 2, 3, 4 S>ExclusiveRange(beforeLow, afterHigh) // для (1, 4) переберет (2, 3) S>Since(low) // для (1) будет перебирать 1, 2, 3, ... до бесконечности
Похоже в Nemerle можно будет всякого такого прикрутить
[]
_>Резюме. В перле приняли правильное решение — перебор элементов массива (без итераторов) foreach и универсальный сишный for.
из Programming Perl:
Ключевое слово foreach служит просто синонимом ключевого слова for, поэтому for и foreach можно использовать взаимозаменяемо и в зависимости от того, которое из них выглядит более удобочитаемым в конкретной ситуации.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
i@len // for (int i = 0; i < len; i++)
i@len@2 // for (int i = 0; i < len; i+=2)
i@@len // for (int i = 0; i <= len; i++)
i@(len+1) // for (int i = 0; i <= len; i++)
gear nuke wrote:
> _>Резюме. В перле приняли правильное решение — перебор элементов массива > (без итераторов) foreach и универсальный сишный for. > > из Programming Perl: > Ключевое слово foreach служит просто *синонимом* ключевого слова for, > поэтому for и foreach можно использовать взаимозаменяемо и в зависимости > от того, которое из них выглядит более удобочитаемым в конкретной ситуации.
Я знаю, но какая лексема применяется — дело второе. Главное — две различные семантические конструкции:
Просто в этом треде обсуждали как лучше перебирать числа от нуля до n — ну не требуется это в большинстве практических
задач, максимум в учебных целях, когда человек ещё не понимает абстракцию "итератор".
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
я не сомневался
_>но какая лексема применяется — дело второе.
Со вторым не соглашусь. В Perl чего только не понапихали, с этим There is more than one way to do it. Казалось бы, что мешает наделать ещё пару десятков этих вариантов for, не пожалели же лишнюю лексему-синоним. А сделали всего 2. Должен же быть в этом всём какой-то смысл (учитывая, что P — это practical)
_>Просто в этом треде обсуждали как лучше перебирать числа от нуля до n — ну не требуется это в большинстве практических _>задач, максимум в учебных целях, когда человек ещё не понимает абстракцию "итератор".
Дык это как раз перебор всех элементов множества.
foreach(@a)
А точнее, вопрос был такой:
как должен выглядить идеальный синтаксис перебора значений из диапазона
А что такое диапазон множества, как не другое множество (срез от первого) ?
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth