Этот пост не фич-реквест, просто интересно обсуждение.
Насколько возможно чисто в макросах реализовать поддержку двусторонних итераторов/генераторов? Это что-то вроде:
Iterator() : Seq[int]
{
mutable x = 42;
while (true)
{
x = yield(x); // yield работает как функция, которая передает аргумент вовне, и возвращает то, что оттуда положат
}
}
Main() : void
{
def numbers = Iterator();
foreach (i in [1..10])
{
WriteLine(numbers[i]); // передаем в Iterator і, получаем оттуда x
}
}
На выходе получается (вроде как) 42, 1, 2, 3, 4, 5, 6, 7, 8, 9. Фича иногда бывает даже полезна.
Ясно, что как минимум надо будет реализовать интерфейс, похожий на IEnumerable, в котором MoveNext принимает параметр. Ещё, соответственно, нужен макрос для yield. Есть какие-то проблемы, что мешають реализовать данное чудо? (кроме не слишком широкой востребованности)
Здравствуйте, catbert, Вы писали:
C>Ясно, что как минимум надо будет реализовать интерфейс, похожий на IEnumerable, в котором MoveNext принимает параметр. Ещё, соответственно, нужен макрос для yield. Есть какие-то проблемы, что мешають реализовать данное чудо? (кроме не слишком широкой востребованности)
Мне кажется, если это обобщить, то получатся просто-напросто корутины. Т.е. чтобы можно было не просто возвращаться значение, а передавать контроль в конкретную функцию. По поводу востребованности — хз. Но, мне кажется, корутины вполне можно реализовать поверх генераторов — последние просто должны возвращать некий дескриптор, описывающий, куда именно нужно совершить переход.
Здравствуйте, catbert, Вы писали:
C>Этот пост не фич-реквест, просто интересно обсуждение.
C>Насколько возможно чисто в макросах реализовать поддержку двусторонних итераторов/генераторов? Это что-то вроде:
C>[nemerle] C>Iterator() : Seq[int] C>{ C> mutable x = 42;
C> while (true) C> { C> x = yield(x); // yield работает как функция, которая передает аргумент вовне, и возвращает то, что оттуда положат C> } C>}
Не очень-то понимаю, причем здесь list comprehensions... Я имею в виду возможность оператора yield возвращать значения.
VD>В снипетах есть ComputationExpressions.
Возможно, yieldcomp как раз можно использовать для реализации. Но он тоже значения вроде бы не возвращает.
Здравствуйте, catbert, Вы писали:
C>Не очень-то понимаю, причем здесь list comprehensions... Я имею в виду возможность оператора yield возвращать значения.
А он разве этого не умеет?
VD>>В снипетах есть ComputationExpressions.
C>Возможно, yieldcomp как раз можно использовать для реализации. Но он тоже значения вроде бы не возвращает.
Тогда опиши свои хотения более подробно. А то я не понял их видимо.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
C>>Не очень-то понимаю, причем здесь list comprehensions... Я имею в виду возможность оператора yield возвращать значения.
VD>А он разве этого не умеет?
Ну, yield вроде как выталкивает (push) значения в вызывающую процедуру. А двусторонний yield может его еще и вытягивать (pull) из вызывающей процедуры. Я думал, Руби так умеет, но там, насколько я погуглил, для достижения pull-эффекта просто yield-ятся ссылки на переменные.
Все иллюстрируется кодом:
def x = yield(a);
То есть, yield становится функцией (точнее, выражением) и возвращает значения.
Такое реализовано в Python 2.5 и хорошо описано тут: http://www.python.org/dev/peps/pep-0342/ В принципе, в том документе много дополнительных фишек описано: возможность останавливать итераторы, вызывать в них исключения.
Двусторонние итераторы — это почти сопрограммы (coroutines), не хватает только возможности для итератора выбирать, в какую процедуру yield-ить. А от сопрограмм, мне кажется, и до продолжений (continuations) в отдельно взятых классах недалеко