Здравствуйте, VladD2, Вы писали:
VD>Если мне, то можно на мыло (в профиле).
VD>Если есть желание сделать это дело доступным для всех, то лучше всего просто расположить код в каталоге snippets. Для того чтобы можно было менять немерловый SVN нужно прислать мне на мыло гуглевый эканут. Я добавлю его в список разработчиков.
Послал тебе вчера со своего гуглового аккаунта. Поучаствовать не против. Например, я мог бы заменить то, что есть сейчас в каталоге snippets/ComputationExpressions. Там сейчас лежит только набросок.
VD>list comprehension и так был, только реализован напрямую в виде макроса:
VD>http://nemerle.googlecode.com/svn/nemerle/trunk/macros/Util.n (смотри module ListComprehensionHelper)
Да, видел. Похоже на хаскелевский list comprehension. Кстати, у них нотация do есть обобщение list comprehension. В F# пошли несколько другим, но похожим путем.
D>>Вот, рабочий пример:
D>>D>> def coll =
D>> comp enumerable
D>> {
D>> mutable i = 0;
D>> while (i < x)
D>> {
D>> yield i;
D>> i ++;
D>> }
D>> }
D>>
VD>Я правильно понимаю, что coll будет иметь тип IEnumerable[int]?
Да, именно. Кстати, в тех исходниках, что я прислал, не хватает одного Delay при генерации коллекции coll в самом начале, когда оборачивается результат. Добавил. В общем, надо изменить метод EnumerableBuilder.Run:
public Run (expr : PExpr) : PExpr
{
<[ EnumerableHelper.Delay (() => $expr) ]>
}
Сейчас есть зависимость от самой сборки ComputationExpressions.dll. Это из-за вспомогательного класса EnumerableHelper. Потом его вынесу в отдельную dll. Будет маленький и независимый ComputationExpression.Runtime.dll.
D>>Можно использовать и yieldcomp. Тогда будет подставляться вся подпоследовательность.
VD>Вот тут я разницу не уловил.
В прямом смысле подставляется подпоследовательность. Примерно так:
def upTo (n : int) : IEnumerable [int]
{
comp enumerable
{
mutable i = 0;
while (i < n)
{
i ++;
yield i
}
}
}
def manyTimes : IEnumerable [int] =
comp enumerable
{
yieldcomp (upTo (2)); // 1 2
yield 100; // 100
yieldcomp (upTo (3)); // 1 2 3
yield 100; // 100
yieldcomp (upTo (10)); // 1 2 3 .. 10
}
Иногда yieldcomp — очень полезная штука. Как и returncomp (aka return! в F#). С точки зрения монады yieldcomp и returncomp очень близки.
D>>Что касается производительности. List comprehension эффективен также как и встроенный в Nemerle. Используется та же самая техника с аккумулятором.
VD>Думаю, встроенный будет все же несколько эффективнее, так как он переписывается в чистые циклы.
Я думаю, что такая же эффективность. Эффективнее просто быть не может. Макрос comp практически не создает ничего лишнего в случае list comprehension. Только работа с аккумулятором в тех местах, где прописан yield и yieldcomp. Сначала все складывается в обратном порядке, а потом в конце вызывается Rev ().
D>> Макрос здесь не имеет накладных расходов. Array comprehension эффективен. Тоже используется аккумулятор. Enumerable comprehension сложнее. Там создаются временные подпоследовательности. Но думаю, что скорость терпима.
VD>Что за подпоследовательности?
В вспомогательном классе EnumerableHelper. Yield оборачивается в вызов Singleton. Yieldcomp подставляется как есть. Когда же соединяем две подпоследовательности, то вторая сначала делается отложенной через Delay, а потом обе подпоследовательности соединяются через Append. Cлучай конструкции while для последовательностей прописываем особо в методе While вспомогательного класса.
Фишка в том, что синтаксический разбор всех вычислительных выражений один и тот же, будь то list comprehension или какое-нибудь продолжение. Генерация же кода настраивается под вычислительное выражение.