Re[6]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 03:51
Оценка:
Здравствуйте, 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 или какое-нибудь продолжение. Генерация же кода настраивается под вычислительное выражение.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.