Вадим 老陆 Румянцев@vadimr
Разработчик аппаратно-программных комплексов
Информация
- В рейтинге
- 1 942-й
- Откуда
- Санкт-Петербург, Санкт-Петербург и область, Россия
- Дата рождения
- Зарегистрирован
- Активность
Специализация
Менеджер проекта, Архитектор программного обеспечения
Ведущий
Восточный никогда не строился для пилотируемых пусков Союзов. Там предполагаются в перспективе пилотируемые пуски Ангары, это совершенно другой стартовый комплекс.
Также и сам Союз не рассчитан на пилотируемые пуски с Восточного, о чём упоминается в статье.
В Scheme это выражается конструкцией
(delay-force expr), которая семантически означает немедленное применениеdelayк результату(force expr)(то есть ленивость после фактического вычисления одного шага), а синтаксически при этом сохраняет хвостовой контекст, который суперпозиция двух функций потеряла бы. Тот же батут, вид сбоку.Так и будет: единица в голове и рекурсивно такой же список в хвосте, вычисление которого отложено.
У рекурсии нет никакой семантики, всё лямбда-исчисление и его ближайшие производные – это чисто синтаксический механизм, чем оно и ценно. Именно про это я вам и говорю. Можно расписать тупо в макроподстановках (бета-редукциях). А вы для объяснения простейшего синтаксического механизма тащите половину языка Питон в виде семантики и реализации.
Очень хорошо, однако в написанном вами коде никакой цикл не выполняется, даже на один шаг, как могло бы показаться невнимательному программисту. Это легко проверить, выполнив следующую программу:
Вас просто ввёл в заблуждение один из приколов языка Питон, когда синтаксическая конструкция
forв теле генератора фактически не является исполняемым циклом, как было бы, если бы дальше по тексту не располагалась конструкцияyield.Поэтому ваши рассуждения о "паузе" не имеют под собой фактических оснований.
Ну и, конечно, никакой паузы в любом случае нет, а код последовательно выполняется, после оператора
yieldисполняется часть кода вызывающей генератор программы, и затем вызывается следующий шаг генератора, что как раз и представляет собой косвенную рекурсию. Но всё это происходит при использовании генератора, а не при его определении.Рекурсия, разумеется, тут не относительно псевдофункции
inner,а относительно шага псевдоцикла.В символическом виде – почему бы и нет. В этом и есть мощь символьных вычислений.
Вычислительный процесс сам по себе не зависит от времени, как и любая другая математическая формула. Это просто связь исходных данных с результатом. Во времени его раскручивает полследовательно работающий компьютер, но это обычно (если не брать системы реального времени) не является существенно важным свойством алгоритма.
Вы можете привязать выполнение тела функции к таймеру, но это не имеет отношения к ленивому вычислению. В ленивом вычислении мы сначала получаем результат функции в абстрактных символах (например, y=sin(x)), а уже потом при необходимости разрешаем эти символы до конкретных значений элементарных типов (т.е. собственно вычисляем).
Ясно, что никакой таймер не позволит вам вычислить бесконечную последовательность.
В каком месте оператора языка Питон
вы видите выполнение цикла? Это просто присваивание переменной gen функционального замыкания, при своём будущем применении вычисляющего первый элемент последовательности и содержащего правило рекурсивного шага к второму элементу.
Нет, конечно, ленивое вычисление не имеет никакого отношения к таймерам. Это просто операционная семантическая интерпретация вызова функции, которая заключается в том, что функция фактически вычисляется не в момент применения, а (в зависимости от идеологии языка) либо тогда, когда эффективно потребуется её результат (например, зависящее от него значение необходимо показать на экране), либо по явному оператору применения (как, например, в случае обращения к генератору для построения фактического списка).
Тут надо понимать, что сама по себе математическая запись
y=f(x)не подразумевает, что прямо тут надо обязательно бросаться что-то считать. И если это делается в некоторых языках программирования, то просто для удобства реализации.Они, кроме того, обеспечивают возможность параллельного вычисления. В то время как параллельный цикл – конструкция, имеющаяся далеко не во всех языках программирования и довольно сложная для применения при императивном стиле, то есть при наличии побочных эффектов.
yield return никак не связан с циклом.
Кстати, это настолько экзотический оператор, что Вы даже набрали его имя с опечаткой, что вполне понятно и простительно. В отличие от применения функции.
Отдельная сущность в языке Python для генератора требуется только по той простой причине, что в его базовой семантике эффективный генератор не описать. Если, как в Scheme, есть ленивый вызов функции общего вида, то и отдельная сущность не нужна. И без всякой отдельной сущности код на Scheme более ясен и компактен, чем на Python.
Сама идея у нас и на западе воспринимается пока в диковинку, но в Китае академик 张钹 Zhang Bo (дедушка китайского ИИ) опубликовал её в своей программной статье на английском языке Toward the third generation artificial intelligence ещё три года назад, из чего следует, что китайцы занимаются ИИ третьего поколения уже много лет.
Да без проблем в подходящем языке.
Вы удивитесь, но многие системы интеллектуального управления как раз крутятся в бесконечной рекурсии в силу использования соответствующих языков, применяемых в символическом ИИ.
Спорно, так как иногда зависит от субъективного опыта, а иногда просто неверно.
Вот выше приводились примеры реализации генератора через псевдоцикл и через рекурсию. Первое вообще в лучшем случае один из десяти программистов понимает в деталях правильно. Второе банально.
Только в кривых компиляторах. Даже банальный gcc одинаково компилирует хвостовую рекурсию и эквивалентный цикл. Хотя, конечно, язык C/C++ (в отличие от многих функциональных языков) этого не гарантирует.
Уже ленивый цикл появился )
Передача контекста из окружающего кода в лямбду – это фундаментальная база лямбда-исчисления. Без неё ФП невозможно.
Даже в не функциональных языках с элементами ФП без этого лямбды были бы во многом лишены смысла. Например, нельзя было бы сделать каррирование при вызове функции высшего порядка типа такого:
Абсолютно верно.
(используем ваш любимый язык).
Вопрос без звёздочки: это генератор?
Вопрос без звёздочки: здесь есть yield?
Вопрос со звёздочкой: здесь есть цикл?
Ну нормально для Middle, я считаю. Для ведущего разработчика надо бы уже в проектных терминах рассуждать, а не в инструментальных.
Это не абстракция, а ложная аналогия. Никакой паузы нет, все вычисления выполняются строго последовательно и непрерывно. Оператор yield точно так же немедленно влечёт своё продолжение, как и любой другой.
Другое дело, что генератор вычисляется лениво. Но это не пауза в выполнении, а просто семантика применения функционального вызова.