Search
Write a publication
Pull to refresh

Comments 43

Увы, в стандарте до сих пор нет хоть какой-то подборки готовых адаптеров итераторов. Зато с 17-го есть зета-функция Римана — ну очень важная и нужная абсолютно всем программистам на С++.

Удивитесь, но она есть и в tensorflow,
Да и добавление математических функций ни у кого не должно вызывать возражений, а так вызов такой функции можно будет эффективно транслировать на графическую карту через OpenAcc.

Это был горький сарказм если что. Про то, что в стандарт засунули то, что могло спокойно сидеть в tensorflow и дальше. Зато нет целой кучи базовых строительных блоков.
Зета-функция, полиномы Лежандра и т.п. безусловно важные и нужные штуки — но применяемые в довольно узкой области.

Там множество комитетов и они фактически независимы.
Вы хотите, что бы был единый комитет согласовывающий все изменения, все нюансы?

Добавление мат функций никак не задерживает процесс принятия других изменений.

Увы, я в курсе, что там куча комитетов.
Я хотел бы, чтобы велась разработка не стандарта, а референсного компилятора с участием всех заинтересованных сторон. Я так же в курсе, что "не судьбец".
То, что их добавление не задерживает принятие стандарта, не повод их в стандарт добавлять. Ещё 200 страниц к талмуду. Причём с пользой для очень узкого круга пользователей.

Из 10 человек, которые писали/пишут на С++ у ВСЕХ(мои знакомые) возникала такая потребность в мат функциях (редко).
А вот потребности в готовых итераторов не возникало ни у кого.

Ладно, давайте закроем тему. Иначе сейчас будем спорить, у кого выборка репрезентативней.

К сожалению, этот "итератор" (на самом деле, генератор) не будет работать со стандартными алгоритмами std::generate и std::generate_n. Особую пикантность ситуации придаёт то, что в том примере, который автор выбрал для демонстрации того, как хорошо "итератор" комбинируется со стандартными алгоритмами, делается как раз то, для чего и предназначены данные алгоритмы. Проще говоря, в примере, который должен был продемонстрировать бесшовную интеграцию со стандартными алгоритмами, автор использует неправильный алгоритм и демонстрирует костыльный способ интеграции с ним.

Гм. Так а что нужно доработать, чтобы он всё-таки заработал со стандартными алгоритмами std::generate и std::generate_n?

Мне кажется, вы всё же немного не справедливы. Генераторы удобны для заполнения коллекций, но не для алгоритмов. Если вам просто надо проивести ряд вычислений или операций над некой последовательностью, тогда запись


for (auto num : numbers(4, 10)) {
    ...
}

намного удобнее, чище, нагляднее и несколько безопаснее, нежели что-то вроде


auto generator = numbers(4, 10);
for (i = 0; i < generator.size(); ++i) {
    auto num = generator();
    ...
}

Запись можно сделать какую угодно. Но всё-таки штука, которая генерирует значения на лету, называется "генератор". А "итераторами" принято называть штуки, которые итерируют по уже существующим значениям. При этом можно совершенно спокойно добавить в генератор поддержку фич итератора. Но, во-первых, желательно, чтобы он при этом оставался генератором (т.е. самим собой). А, во-вторых, нужно понимать, что ты делаешь генератор, мимикрирующий под итератор, а не настоящий итератор.


Ещё Конфуций призывал называть вещи своими именами. Очень незаурядный, надо сказать, человек был. В историю вошёл благодаря своей мудрости.

Но всё-таки штука, которая генерирует значения на лету, называется «генератор». А «итераторами» принято называть штуки, которые итерируют по уже существующим значениям.
Все генераторы являются итераторами, и они не связаны с генерацией значений на лету.
Ещё Конфуций призывал называть вещи своими именами.
Только определения при этом нужно использовать общепринятые, иначе они никак не помогут в общении.
Человек есть животное на двух ногах, лишённое перьев.
— Платон

Отнюдь. Генератор псевдослучайных чисел не является итератором. Также итератором не является генератор электрического тока. Генератор документации doxygen не является итератором, хотя часто применяется в итеративной разработке. (Наверное, в нём всё-таки есть что-то от итератора.)


Тем не менее, все эти вещи называются генераторами. Совпадение? Не думаю. Всё дело в том, что они что-то — внимание! — ГЕНЕРИРУЮТ. Т.е. они сами являются источником этого чего-то. Применительно к программированию этим чем-то являются значения… именно их генерируют генераторы… т.е. генераторы сами являются источником значений. В отличие от итераторов, которые итерируют по тем значениям, которые являются по отношению к ним внешними.

Генератор псевдослучайных чисел не является итератором. Также итератором не является генератор электрического тока. Генератор документации doxygen не является итератором, хотя часто применяется в итеративной разработке.
Это все очень хорошо, но в программировании есть отдельный термин «генератор» не имеющий никакого отношения к перечисленному, и именно о нем сейчас идет речь.
т.е. генераторы сами являются источником значений. В отличие от итераторов, которые итерируют по тем значениям, которые являются по отношению к ним внешними.
По такой логике и переменная не переменная, если значение ей не переменять. Но как я и говорил выше, следует использовать устоявшиеся значения терминов, а не выдумывать новые, иначе никто не поймет что имелось ввиду.

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


Переменная, значение которой вы изменить можете, но не делаете этого, называется переменной. А вот переменная, значение которой вы не можете изменить, уже называется иначе — константой. Для названий гораздо большее значение имеет то, чем предмет является объективно, а не то, как вы с ним взаимодействуете.


Когда-то давно я читал книгу о том, как устроено американское школьное образование. Тогда мне казалось невероятным, что образование может быть устроено таким образом. Ведь, по сути, это не было образованием как таковым. Дети не получали в школе даже самых элементарных знаний. Теперь я уже не так уверен. Всё-таки какие-то знания американские выпускники получали. По крайней мере, они точно должны понимать, что генераторы генерируют, а итераторы итерируют. Ведь они там чуть ли не каждую неделю пишут какое-нибудь эссе. А значит какой-то базовый уровень владения языком у них должен быть.

Как бы вам не хотелось того, чтобы генераторы в программировании не имели никакого отношения к иным генераторам, они его всё-таки имеют
Вас куда-то относит от темы. Я вам о том, что не соотносил генераторы электрического тока с итераторами, а вы в ответ пытаетесь угадывать чего я хочу…
Переменная, значение которой вы изменить можете, но не делаете этого, называется переменной. А вот переменная, значение которой вы не можете изменить, уже называется иначе — константой. Для названий гораздо большее значение имеет то, чем предмет является объективно, а не то, как вы с ним взаимодействуете.
Правильно. Поэтому генераторы остаются генераторами, даже если они вообще не возвращают никаких значений, но потому что могут в принципе. Генераторы — это ассиметричные сопрограммы. Или, как еще говорят, функции с поведением итератора. Ничего более.
А значит какой-то базовый уровень владения языком у них должен быть.
К чему вообще это и весь последний абзац?

Сопрограммы — это просто один из способов реализации генераторов. Причём характерный только для питона. В других языках сопрограмм либо до сих пор нет, либо они появились недавно, а ведь генераторы и раньше как-то делали. Более того, лично я считаю, что сопрограммы вообще не являются ничем, кроме синтаксического сахара. Ничего принципиального нового они не привносят. Промежуточное состояние приостановленной функции я без труда могу хранить в отдельной структуре и передавать его в каждый следующий вызов функции. Я имею в виду то, что я могу сделать это непринуждённо… т.е. вообще не напрягаясь. Это не то же самое, что эмулировать таблицу виртуальных методов в Си. Последнее представляет собой определённый геморрой. А вот сопрограммы — "это изи" (как говорит современная молодёжь).


Последний абзац был лирическим отступлением. Это такой повествовательный приём. Не берите в голову. Считайте, что я сделал это отступление просто потому, что могу...

Сопрограммы — это просто один из способов реализации генераторов.
Эмм, нет. Откуда вы берете такую дезинформацию? Можно привести пример книги или авторитетной статьи, которая это утверждает?
Причём характерный только для питона
У питона есть официальный референс, и там прямым текстом сказано чем в этом языке считается генератор. А именно — «A function which returns a generator iterator. It looks like a normal function except that it contains yield expressions for producing a series of values usable in a for-loop or that can be retrieved one at a time with the next() function.».
В других языках сопрограмм либо до сих пор нет, либо они появились недавно
Это утверждение неверно. Генераторами в Perl, PHP, Ruby, JS официально считается то же, что и в Python. Неофициальные библиотеки для других языков используют эту же интерпретацию. При этом есть десятки других языков с корутинами, но термин «генератор» они не используют в принципе, даже в случаях в которых предлагаете его использовать вы. И почти все вышеописанное появилось далеко не вчера. Такое же значения термина повсеместно и на stackowerflow, а википедия напрямую сравнивает между собой корутины и генераторы. Так почему мы должны считать генераторами что-то другое, чем описанной мной выше?
Более того, лично я считаю, что сопрограммы вообще не являются ничем, кроме синтаксического сахара.
Тогда и все языки программирования следует считать синтаксическим сахаром над бинарным исполняемым кодом. Ведь все что они делают можно повторить и на нем.

Я вообще не понимаю, почему мы говорим о сопрограммах и корутинах. Да, они используются для создания генераторов, потому что это удобно. Кто с этим спорит? Нужно отойти на шаг назад. В чём вообще исходная проблема?

Я вообще не понимаю, почему мы говорим о сопрограммах и корутинах.
Потому что по общепринятой терминологии генератор — это усеченная в возможностях сопрограмма. Все возможные пруфы и аргументы были предоставлены, но вы почему-то отказываетесь это принимать.
Да, они используются для создания генераторов
Нет, не используются. Вы хотя бы переходили по ссылкам, что я скинул? Я даже один абзац полностью в комментарий вставил, чтобы вы не пропустили.
В чём вообще исходная проблема?
В прививании термину «генератор» самопальное значение.

Мне не нужно переходить по ссылкам, чтобы понимать, что в общем смысле генератор — это то, что генерирует значения. Ну, а если говорить конкретно про питон, то там это слово используется в специальном значении. Согласно приведённой вами же цитате, в питоне генератором называется функция, которая возвращает генерирующий итератор. Тем не менее, даже эта узкая питоновская трактовка всё равно связана с генерацией значений. И это неудивительно. Генерация значений — это ключевой момент в генераторе. Не важно, что он делает в дополнение к этому, но он обязательно должен делать что-то связанное с генерацией значений. В противном случае это не генератор.

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

Наконец-то! Удивительно, что потребовалось столько времени, чтобы понять, что на таком фуфле меня не развести. В том, что генераторы генерируют значения, я абсолютно уверен.

Раз уж вспомнили Платона, то легко представить, что в его мире идей находится бесконечная таблица чисел Фибоначчи, и этот объект — именно итератор, ходящий по ней. Поэтому идея такого итератора не вызывает у меня отторжения.

Если посмотреть на сигнатуры, то генератор — это нечто, имеющее operator(), а итератор — operator++. То есть, для итератора логично предположить и симметричный operator--. Этим я и предлагаю отличать генераторы от итераторов — наличием вычислимого (возможно, трудновычислимого) предыдущего элемента.

Например, у односвязного списка есть предыдущий элемент, хотя нет эффективного operator--, а у последовательности случайных чисел — предыдущий не имеет смысла.

В мире идей Платона генератор псевдослучайных чисел тоже имел бы свою таблицу чисел и ходил бы по ней. Значит ли это, что его следует называть "итератор по псевдослучайным числам"? Или всё-таки мир идей Платона имеет не такое существенное значение?


Наличием operator-- отличаются разные типы итераторов — bidirectional и forward.

Я предложил семантическое различие. Реализация может быть любой.

Если для задачи важно, какое псевдослучайное значение было перед этим (например, при взломе криптосистем) — это итератор. Если вы работаете с псевдослучайными последовательностями как со случайными — это генератор.

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


Само по себе это не бред. Но в сочетании с отсылкой к Платону образуется неконсистентная позиция. В споре "номиналисты vs. реалисты" вы, как бы, находитесь сразу на обеих сторонах. Существование мира идей Платона — это реализм. А представление о том, что самих идей в чистом виде не существует, а существуют лишь прикладные понятия (отражения на стенах платоновской пещеры) — это номинализм.


Кроме того, не совсем понятно, зачем нам нужно другое семантическое различие, когда одно у нас уже есть. Генераторы — это штуки, которые генерируют значения. Т.е. мы не привязываем к ним уже существующие значения. А итераторы — это штуки, которые итерируют по заранее подготовленному набору значений. Неизбежным следствием того, что они итерируют является то, что они не генерируют. А это крайне важно с точки зрения методологии. Дистинктивность — необходимое условие существования отдельного понятия. Если у вещи есть отдельное название, то значит обязательно должно существовать какое-то дистинктивное свойство, отличающее эту вещь от всех прочих.

Если название вещи будет зависеть не от её собственных свойств, а от того способа взаимодействия с вещью, который используется в данный момент, то это будет название не самой этой вещи, а всего лишь название её отображения, имеющее смысл только в рамках текущей задачи.
Есть курица, она бегает, щиплет траву, кудахтает и несёт яйца.
А ещё есть еда, которая куриные крылья в кляре, куриный бульон и салат из копчёной куриной грудки с ананасами. А ещё еда — это говядина, фрукты, зелень, и если очень приспичит, кожаный ремень.

То же самое и тут, у нас есть итератор, позволяющий передвигаться по известной последовательности. Как она представлена, контейнером или алгоритмом, в общем, не важно, если i-тый шаг всегда будет возвращать одно и то же i-тое значение. Числа Фибоначчи, цифры числа Пи или числа Эйлера, от того, как вы их храните, их сущность и значение не меняются.
Другое дело, генератор, выходные значения которого зависят от начального состояния. Например, генератор псевдослучайных величин в зависимости от инициализатора может выдавать непересекающиеся множества. Генераторы, однако — тоже итераторы, просто их мерность больше, чем мерность публичного итератора.

Так что в данном случае вы не правы.

Ещё как важно. Когда последовательность представлена контейнером, и вы итерируете непосредственно по элементам этой последовательности — это простой итератор. А когда последовательность задана функцией, и вы итерируете по значениям аргумента, генерируя сами элементы на лету — это генерирующий итератор (т.е. генератор).

Допустим. Интересно, если бы значения последовательности кешировались бы в контейнер, вы бы по прежнему настаивали на том, что это генератор, или уже перешли бы к термину «итератор с инициализатором»? Или «генератор с буфером»? И где бы прошла грань? По линии раздела итератора?

Я веду к тому, что граница между итераторами и генераторами очень зыбкая, и уповать только на «вычисление элемента» — весьма глупо. Есть, например, итераторы по шифрованным последовательностям, они в куда? Вроде бы контейнеры, но без начальной инициализации ключом не работают, да и производят вычисления над каждым очередным элементом. Именно поэтому лично мне использование термина «генератор» в этом контексте кажется глупым. Если уж и разделять генераторы и итераторы, то по возможности контролировать момент перехода от текущего значения к следующему. Иначе разделение просто нельзя провести и тему можно закрывать.

Так они и кешируются в том генераторе, который описан в статье. Не все, а только последние два. Но принципиальной разницы нет. Это просто особенность реализации.


Граница очень чёткая. Генератор создаёт элементы последовательности сам, а итератор ходит по готовым… они были созданы внешней по отношению к нему логикой. По большому счёту, в этом и заключается предназначение любого итератора — отделить логику обхода элементов от самих элементов. Если она не отделена, то значит это не итератор.


Итератор по шифрованной последовательности я бы отнёс к итераторам. Процесс расшифровки в большей степени относится к обходу, чем к хранению.

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

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

Тогда я немного уточню свою позицию. Чистый итератор — это когда вообще нет генерации. Только итерация по готовым значениям. (I have a pen.) Чистый генератор — это когда никакой итерации нет вообще. Подаём на вход аргумент и получаем на выходе соответствующее ему значение. (I have an apple.) Соединяем их вместе и получаем генерирующий итератор (apple-pen).


И, по-хорошему, для итераторов по шифрованным последовательностям нужно отдельное название — трансформирующий итератор. Ведь, по сути, они трансформируют значения из шифрованной формы в расшифрованную. Формула, которая в них содержится, работает исключительно с формой значений, а не с их содержанием. И такой трансформирующий итератор аналогичным образом состоит из двух частей — чистого трансформатора (pineapple) и чистого итератора (pen).


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

Лично меня устраивает такой подход, однако он перечёркивает ваш корневой комментарий.
В таком случае технически ph_piter прав в своей терминологии, хоть и немного не точен. (I have a hub). Ваше же замечание хоть и имеет толику смысла, всё же несправедливо в своей категоричности (I have some porn). Было бы неплохо, если бы вы как-либо популяризировали этот подход, добавив статью на вики, но в рамках комментов тема раскрыта.
[ roscomnadzor ]

Мой наезд на автора вызван тем, что он неверно расставил акценты. Сделав генерирующий итератор, он назвал его итератором. Как будто, итераторность — это главное свойство. В то время как в итераторной части нет абсолютно ничего интересного, а вся суть заключается в генераторном аспекте.


Со своей стороны я готов признать лишь то, что был неточен в тот момент, когда назвал генераторный итератор просто генератором. Просто мне кажется очевидным, что когда говоришь о генераторе в контексте итеративного процесса, само собой подразумевается, что это генерирующий итератор. Лично я никогда не заморачиваюсь на точности терминологии. Когда привязываешь генератор к последовательности или контейнеру, понятно, что он становится итерирующим. Нет смысла это как-то специально оговаривать. Можно спокойно продолжать называть его генератором.

В общем-то вы сами запутались в своих собственных абстракциях.
Все значения последовательности Фибоначчи вполне «уже» существуют, не зависимо от того посчитали мы их или нет. У них есть вполне определенная очередность. Так что по ним вполне возможно итерировать как вперед так и назад.
Генераторы скщнствуют для более абстрактных «последовательностей», для которых очередность элементов либо не определена либо не имеет смысла. Два генератора невозможно сравнить, два итератора — вполне.

А, ну-ка, проитерируйте по числам Фибоначчи назад больше, чем на два шага, значения которых сохранены в генераторе.


На самом деле, мне, конечно, понятно, из-за чего у вас (и не только) возникает путаница. Описанный автором генератор одновременно является и итератором по неявно существующей последовательности натуральных чисел (номеров чисел Фибоначчи). И только в этой его итераторной части его имеет смысл сравнивать с другим итератором. Та же часть, которая отвечает непосредственно за числа Фибоначчи, безусловно, является генератором. И сравнивать её с чем-либо не имеет смысла. Причём даже сам автор это понимает. В его ограничительном итераторе предыдущие числа равны нулю. Полноценным генератором он не является. Вы не можете получить из него соответствующее число Фибоначчи. Хотя можете двигать его как вперёд, так и назад, меняя тем самым границу диапазона.

А, ну-ка, проитерируйте по числам Фибоначчи назад больше, чем на два шага, значения которых сохранены в генераторе.
Это несложно: Fn-2 = Fn - Fn-1

Ну да, логично. Зная два соседних числа, можно продвигаться назад точно так же, как и вперёд. Об этом я не подумал. Но тогда возникает другой вопрос. Почему чувак из статьи сделал только forward-итератор? Почему не сделал bidirectional? Или хотя бы ещё и reverse отдельно… и функции перехода от forward к reverse и обратно? Ведь если это не генератор, а итератор, то все эти вещи, как бы, тоже не помешают...

Давайте переведем хотя бы первый пост Эрика? Желающие плюсуют

Уже есть перевод чуть более старого цикла: https://habrahabr.ru/company/cpp_russia/blog/264201/
И поскольку тема диапазонов у Эрика центральная, скорее всего в новом цикле нет ничего нового. Точно сказать не могу, поскольку читал только новый цикл.

Sign up to leave a comment.