Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 17.04.10 07:48
Оценка:
Есть тип выражения expr : FixedType. Также есть полиморфный тип comp : TypeVar. Задача состоит в том, что нужно узнать, удовлетворяет ли тип expr типу comp. Все типы получаются динамически во время компиляции.

Сейчас использую проверку expr.TryRequire (comp) по аналогии с реализацией макроса foreach. Но такая проверка у меня невсегда срабатывает.

Например, полиморфный тип comp может выглядеть как void -> option [A]. Тогда если expr есть void -> option [?], то проверка срабатывает. Но если на вход поступает expr с типом void -> option [int-], то проверка обламывается, а не хотелось бы. В чем проблема и как ее решить? Кстати, а что такое int-?
Re: Как определить принадлежность генерику?
От: hardcase Пират http://nemerle.org
Дата: 17.04.10 08:10
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Кстати, а что такое int-?


Макросы 4 Часть:
Автор(ы): Владислав Юрьевич Чистяков
Дата: 03.09.2009
В данной части статьи рассказывается о том, как работает система вывода типов Nemerle, о том, как с ней могут взаимодействовать макросы Nemerle, и что это дает


Строковое представление переменной типа (выводимое также в отладчике) – это фактически значение свойства Hint, обработанное специальным образом. Свежие переменные обозначаются визуально как вопросительный знак – «?». Если для переменной задана только верхняя граница, то в конце к имени типа дописывается знак минус – «-». Если задана только нижняя граница, то к имени типа дописывается «+». Если же заданы и верхняя граница, и нижняя, то его строковое представлением будет выглядеть как «(L TILL H)», где L – это тип нижней границы, а H – верхней.

/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 17.04.10 09:25
Оценка:
Здравствуйте, hardcase, Вы писали:

D>>Кстати, а что такое int-?


H>Макросы 4 Часть:
Автор(ы): Владислав Юрьевич Чистяков
Дата: 03.09.2009
В данной части статьи рассказывается о том, как работает система вывода типов Nemerle, о том, как с ней могут взаимодействовать макросы Nemerle, и что это дает


Спасибо. Просмотрел. Все равно для меня остается непонятным, почему для void -> option [int-] не срабатывает TryRequire по более общему типу void -> option [A]. Ведь последний является нижней границей для первого. Или нет? А главное, что поменять, чтобы подобная проверка срабатывала?
Re[3]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 17.04.10 13:46
Оценка:
Вопрос остается окрытым. Тем временем, внутри реализации метода Require класса FixedType (файл MType.n) нашел такие неоднозначные строки:

  match ((this, t)) {
    ...
    | (Fun (f1, t1), Fun (f2, t2)) =>
      // f2.Require (f1) && t1.Require (t2)
      f1.Unify (f2) && t1.Unify (t2)


Как я понимаю, срабатывает именно эта ветка, поскольку имеем функцию void -> option[int-]. Очень сильно смущает закомментированная часть. Что это может значить?
Re[4]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 17.04.10 14:21
Оценка:
Мне кажется, что в этом фрагменте ошибка. Реальное условие должно быть более мягким. Что-нибудь вроде:

  match ((this, t)) {
    ...
    | (Fun (f1, t1), Fun (f2, t2)) =>
      // f2.Require (f1) && t1.Require (t2)
      // f1.Unify (f2) && t1.Unify (t2)
      f1.Unify (f2) && t1.IsGeneralizedBy (t2)


где t1.IsGeneralizedBy (t2) <=> t1 — результат инстанцирования обобщенного t2 или t1 == t2.

Что думаете?
Re[5]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 17.04.10 17:57
Оценка:
Ну, все. Всем спасибо за помощь! Разобрался. Компилятор был прав. Теперь это я понял. Еще понял, что мне нужна была другая постановка задачи. Меня интересует ослабленный тип, где все верхние границы убраны. Пришлось написать проверку вручную. Меня, в общем, интересует, может ли данное выражение хотя бы гипотетически иметь такой-то тип. Если да, тогда применяется совершенно другая генерация кода. Здесь лучше ошибиться в пользу гипотезы.
Re: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.04.10 19:43
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Например, полиморфный тип comp может выглядеть как void -> option [A]. Тогда если expr есть void -> option [?], то проверка срабатывает. Но если на вход поступает expr с типом void -> option [int-], то проверка обламывается, а не хотелось бы. В чем проблема и как ее решить? Кстати, а что такое int-?


Типы A и int не совместимы. Стало быть void -> option[A] и void -> option[int-] тоже.

Тут компилятор совершенно прав.

Лучше опиши задачу более детально.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.04.10 19:45
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Ну, все. Всем спасибо за помощь! Разобрался. Компилятор был прав. Теперь это я понял. Еще понял, что мне нужна была другая постановка задачи. Меня интересует ослабленный тип, где все верхние границы убраны.


В твоем примере верхние границы не причем. У тебя вложенный параметр типа совершенно не совпадает. Может быть тебе нужно было сравнивать тип с чем-то воде void -> option[?] где "?" — это любой тип? Тогда нужно было сначала сформировать тип где вкачетве параметра типа option[T] задан VarType.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 20.04.10 05:42
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Лучше опиши задачу более детально.


Наверное, забыл упомянуть, что A — параметр типа. Поэтому int должен соответствовать. Но я так понял, что int- означает, что здесь может вывестись int, а может и нет. Никаких гарантий еще нет. Как сложатся звезды. Поэтому int- не будет ни TryRequire, не TryUnify для A. (я правильно понимаю?)

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

Я все пекусь о тех самых вычислительных выражениях. Еще раз перечитал спеки F# и понял, что "монадность" выражения можно целиком определить по синтаксическому разбору без привлечения вывода типов и без Typer.DelayMacro. Эта монадность возникает только в выражениях let!, do! и use! Все. Если какое-то выражение вне этого шаблона будет действительно иметь монадический тип, то оно будет вычислено, а затем просто проигнорировано, о чем будет выдан соответствующий warning компилятора. Вот, зачем нужен do!. Короче говоря, все можно решить гораздо проще. Но над этим стоит еще подумать.

Кстати, мне не удалось ввести синтаксическую конструкцию def!. Когда делаю так

  public macro @bind (_expr)
  syntax ("def", "!", _expr) { <[ () ]> }


то компилятор уже в другой сборке начинает ругаться при разборе обычных def. Он начинает ожидать "!". Сейчас думаю использовать такие ключевые слова с добавкой comp: defcomp, usingcomp, docomp, returncomp и yieldcomp. Но с восклицательным знаком выглядело бы идиоматичнее и красивее.
Re[3]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 20.04.10 05:57
Оценка:
Да, забыл. Монадность еще возникает в return! и yield! То есть, достаточно одного синтаксического разбора.
Re[3]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.04.10 13:51
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Наверное, забыл упомянуть, что A — параметр типа. Поэтому int должен соответствовать. Но я так понял, что int- означает, что здесь может вывестись int, а может и нет.


Параметров типов в конкретных типах быть не может. Они заменяются свободными переменными типов (VarType).

D>Никаких гарантий еще нет. Как сложатся звезды. Поэтому int- не будет ни TryRequire, не TryUnify для A. (я правильно понимаю?)


int- — это int или его базовые классы (интерфейсы в данном случае).

Проблема может быть в том, что ты получаешь не тип со свободной переменной, а используешь не подставленный (так что ли его назвать?) тип.

D>Первоначально мне нужно было хотя бы гипотетическое соответствие. То есть, может ли выражение иметь такой-то тип. В общем, взял код FixedType.Unify и просто переписал под себя. Работает. Но теперь я понял, что и это мне не нужно.


Ну, ты уж разберись, что нужно.

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

D>Я все пекусь о тех самых вычислительных выражениях. Еще раз перечитал спеки F# и понял, что "монадность" выражения можно целиком определить по синтаксическому разбору без привлечения вывода типов и без Typer.DelayMacro.


Это хорошо, так как макро будет проще, а чем проще код тем он надежнее.
В прочем знание типов может расширить возможности или сделать код гибче.

D> Эта монадность возникает только в выражениях let!, do! и use! Все.


Вот и мне так показалось. По этому я был довольно удивлен услышив от тебя о необходимости анализа типов.

D>Кстати, мне не удалось ввести синтаксическую конструкцию def!. Когда делаю так


D>
D>  public macro @bind (_expr)
D>  syntax ("def", "!", _expr) { <[ () ]> }
D>


D>то компилятор уже в другой сборке начинает ругаться при разборе обычных def.


Жаль. Надо будет посмотреть, может можно что-то в компиляторе подправить, чтобы он пропускал такой синтаксис.

D> Он начинает ожидать "!". Сейчас думаю использовать такие ключевые слова с добавкой comp: defcomp, usingcomp, docomp, returncomp и yieldcomp. Но с восклицательным знаком выглядело бы идиоматичнее и красивее.


Можно сделать так:
  public macro @bind (_expr)
  syntax ("!!", "def", _expr) { <[ () ]> }

и соответственно использование:
!!def a = ...;
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 20.04.10 16:45
Оценка: 138 (1)
Здравствуйте, VladD2, Вы писали:

VD>А вообще, если код не закрыт, то лучше дал бы ссылку на него или прислал бы мне преокт, а я бы поглядел и подправил.


Я могу прислать старый, но гораздо интереснее новый, о котором ниже. Кстати, куда его слать? Лицензия BSD как у поляков.

VD>Жаль. Надо будет посмотреть, может можно что-то в компиляторе подправить, чтобы он пропускал такой синтаксис.


Пока остановился на defcomp и тому подобном. Comp можно воспринимать как сокращение от computation или comprehension.

VD>Можно сделать так:

VD>
VD>  public macro @bind (_expr)
VD>  syntax ("!!", "def", _expr) { <[ () ]> }
VD>

VD>и соответственно использование:
VD>
VD>!!def a = ...;
VD>


Фу, восклицательные знаки впереди не ком-иль-фо.

Сейчас у меня обрабатываются конструкции def, defcomp (let! в F#), mutable, return, returncomp (return! в F#), yield, yieldcomp (yield! в F#), if, when, unless и while. Сделал list, array и enumerable comprehension по аналогии с F#. Enumerable значит, что генерится значение типа IEnumerable[T]. В F# это будет seq.

Вот, рабочий пример:

    def coll = 
      comp enumerable
      {
        mutable i = 0;
        while (i < x)
        {
          yield i;
          i ++;
        }
      }


Можно использовать и yieldcomp. Тогда будет подставляться вся подпоследовательность. Потом постараюсь найти интересные примеры.

List comprehension выглядит как comp list {...}. Array comprehension — comp array {...}. Enumerable — comp enumerable {...}. Общая схема — comp builder {...}, где builder должен быть объектом, реализующим нужные методы как в F#. Генерацию можно переопределить.

Что касается производительности. List comprehension эффективен также как и встроенный в Nemerle. Используется та же самая техника с аккумулятором. Макрос здесь не имеет накладных расходов. Array comprehension эффективен. Тоже используется аккумулятор. Enumerable comprehension сложнее. Там создаются временные подпоследовательности. Но думаю, что скорость терпима.
Re[5]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.04.10 17:32
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Я могу прислать старый, но гораздо интереснее новый, о котором ниже. Кстати, куда его слать? Лицензия BSD как у поляков.


Если мне, то можно на мыло (в профиле).

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

D>Пока остановился на defcomp и тому подобном. Comp можно воспринимать как сокращение от computation или comprehension.


Ну, в общем-то это все ерунда. Синтаксис можно потом улучшить. Главное чтобы это все работало как надо.

D>Фу, восклицательные знаки впереди не ком-иль-фо.


А мне нравится! (с)

D>Сейчас у меня обрабатываются конструкции def, defcomp (let! в F#), mutable, return, returncomp (return! в F#), yield, yieldcomp (yield! в F#), if, when, unless и while. Сделал list, array и enumerable comprehension по аналогии с F#. Enumerable значит, что генерится значение типа IEnumerable[T]. В F# это будет seq.


list comprehension и так был, только реализован напрямую в виде макроса:
http://nemerle.googlecode.com/svn/nemerle/trunk/macros/Util.n (смотри module ListComprehensionHelper)

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>


Прикольно!

Вот видишь, а ты сомневался, что на макросах такое возможно .

Я правильно понимаю, что coll будет иметь тип IEnumerable[int]?

D>Можно использовать и yieldcomp. Тогда будет подставляться вся подпоследовательность.


Вот тут я разницу не уловил.

D>Потом постараюсь найти интересные примеры.


D>List comprehension выглядит как comp list {...}. Array comprehension — comp array {...}. Enumerable — comp enumerable {...}. Общая схема — comp builder {...}, где builder должен быть объектом, реализующим нужные методы как в F#. Генерацию можно переопределить.


D>Что касается производительности. List comprehension эффективен также как и встроенный в Nemerle. Используется та же самая техника с аккумулятором.


Думаю, встроенный будет все же несколько эффективнее, так как он переписывается в чистые циклы.

D> Макрос здесь не имеет накладных расходов. Array comprehension эффективен. Тоже используется аккумулятор. Enumerable comprehension сложнее. Там создаются временные подпоследовательности. Но думаю, что скорость терпима.


Что за подпоследовательности?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
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 или какое-нибудь продолжение. Генерация же кода настраивается под вычислительное выражение.
Re[7]: Как определить принадлежность генерику?
От: WolfHound  
Дата: 21.04.10 09:18
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Послал тебе вчера со своего гуглового аккаунта. Поучаствовать не против. Например, я мог бы заменить то, что есть сейчас в каталоге snippets/ComputationExpressions. Там сейчас лежит только набросок.

Меняй.

D>В прямом смысле подставляется подпоследовательность. Примерно так:

хъ
D>Иногда yieldcomp — очень полезная штука. Как и returncomp (aka return! в F#). С точки зрения монады yieldcomp и returncomp очень близки.
А вот тут ИМХО можно смотреть на типы.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 10:00
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Меняй.


OK. Как будет доступ.

D>>Иногда yieldcomp — очень полезная штука. Как и returncomp (aka return! в F#). С точки зрения монады yieldcomp и returncomp очень близки.

WH>А вот тут ИМХО можно смотреть на типы.

Думаю, что можно и без этого. Даже хотелось бы, чтобы сохранить для пользователя возможность переопределять генерацию кода. По идее должен быть тип монады. В случае (1) enumerable comprehension это проверяется. В случае (2) общего билдера все определяется типом задаваемых методов YieldComp и ReturnComp. Если же кастомный билдер сам генерит код (3), то все будет так, как ему вздумается. В случае (4) list и array comprehension на типы забивается. Считается, что идет работа непосредственно с кодом, который меняет аккумулятор. Поэтому как бы тип монады вытекает сам собой. Значение в монаде — это сам код PExpr для list и array comprehension.

Тут выходит интересная вещь с конструкцией for для монадического выражения. Может быть еще немонадический for — там просто тупо подставляется сам for. В общем случае монадический for будет преобразован в foreach. Придется искусственно создавать объект типа IEnumerable[_]. Знаю как это можно сделать через ленивый поток (stream). На стек возвратов это не будет влиять.

В общем, получается довольно интересная вещь, которая до фига рутины автоматизирует. Особенно в случае enumerable comprehension. Я посмотрел рефлектором — там столько лямбд и замыканий создается...
Re[9]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 10:15
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>>>Иногда yieldcomp — очень полезная штука. Как и returncomp (aka return! в F#). С точки зрения монады yieldcomp и returncomp очень близки.

WH>>А вот тут ИМХО можно смотреть на типы.

Немного гоню. Для list и array comprehension тоже проверяется тип по аккумулятору. Он должен быть единым. А вот билдер, генерирующий сам код, может делать, что угодно с yieldcomp и returncomp, также как и с yield и return. Просто эти конструкции фиксирует сам факт наличия монады для всех зависимых выражений, что может влиять на генерацию. Но в ядре макроса comp сами типы не проверяется, кроме, может быть, самой последней стадии — оборачивания значения в конечный результат. Но там особая история.
Re[9]: Как определить принадлежность генерику?
От: WolfHound  
Дата: 21.04.10 10:52
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>В случае (2) общего билдера все определяется типом задаваемых методов YieldComp и ReturnComp.

А зачем вообще нужны YieldComp и ReturnComp?
Ведь мы можем просто использовать перегруженные Yield и Return и таким образом избавиться от лишних ключевых слов.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 11:31
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, dsorokin, Вы писали:


D>>В случае (2) общего билдера все определяется типом задаваемых методов YieldComp и ReturnComp.

WH>А зачем вообще нужны YieldComp и ReturnComp?
WH>Ведь мы можем просто использовать перегруженные Yield и Return и таким образом избавиться от лишних ключевых слов.

Проблема в том, что YieldComp/ReturnComp — получают уже значения в монаде, а Yield/Return только создают монаду по заданному аргументу. По идее ReturnComp (m) = builder.Bind (m, x => builder.Return (x)). Но так делать неразумно. Чаще всего ReturnComp (m) просто превращается в m. В случае вычисления с Yield/YieldComp метод Bind может быть и не определен. Поэтому непонятно как выводить YieldComp из Yield.

К тому же, так сделано в F# Должен сказать, что Дон Сайм очень хорошо все придумал и обдумал детали. Удивительно просто.
Re[10]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 11:35
Оценка:
Здравствуйте, WolfHound, Вы писали:

D>>В случае (2) общего билдера все определяется типом задаваемых методов YieldComp и ReturnComp.

WH>А зачем вообще нужны YieldComp и ReturnComp?
WH>Ведь мы можем просто использовать перегруженные Yield и Return и таким образом избавиться от лишних ключевых слов.

А главное, что YieldComp и ReturnComp обозначают, что в таком то месте есть монада. Это влияет на генерацию кода в целом. И не нужны типы. Все уже просчитано до нас
Re[11]: Как определить принадлежность генерику?
От: WolfHound  
Дата: 21.04.10 12:20
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Проблема в том, что YieldComp/ReturnComp — получают уже значения в монаде, а Yield/Return только создают монаду по заданному аргументу.

Это не проблема. Это решение.
Ибо значение и монада имеют разные типы и как следствее работает перегрузка.
Мы просто определяем два метода Yield но один принимает значение, а второй монаду. Тоже для остальных методов.
Дальше механизм разрешения перегрузки разберется.

D>К тому же, так сделано в F#

А ты уверен что это не произошло из-за ограничений самого F#?

D>Должен сказать, что Дон Сайм очень хорошо все придумал и обдумал детали. Удивительно просто.

Просто для кого? Лично я не хочу видеть кучу ключевых слов которых может и не быть.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[12]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 12:34
Оценка:
Здравствуйте, WolfHound, Вы писали:

D>>Проблема в том, что YieldComp/ReturnComp — получают уже значения в монаде, а Yield/Return только создают монаду по заданному аргументу.

WH>Это не проблема. Это решение.
WH>Ибо значение и монада имеют разные типы и как следствее работает перегрузка.
WH>Мы просто определяем два метода Yield но один принимает значение, а второй монаду. Тоже для остальных методов.
WH>Дальше механизм разрешения перегрузки разберется.

Не-не, так нельзя. Это очень разные функции. Этому меня еще хаскель научил.

WH>А ты уверен что это не произошло из-за ограничений самого F#?


Не вижу здесь ограничений. У них трудно определить монадный трансформер. Это действительно ограничение. А в остальном, все очень логично.

WH>Просто для кого? Лично я не хочу видеть кучу ключевых слов которых может и не быть.


Можно просто не определять и не использовать ReturnComp и YieldComp в случае чего. Это факультативно.

А необходимость их следует хотя бы из array comprehension, для которого

yield $x      =>  $(acc : Name).Add ($x)
yieldcomp $x  =>  $(acc : Name).AddRange ($x)


И я не представляю как одно можно было бы выразить через другое в общем случае... И то, и другое — must have однозначно.
Re[13]: Как определить принадлежность генерику?
От: WolfHound  
Дата: 21.04.10 13:02
Оценка: +1
Здравствуйте, dsorokin, Вы писали:

D>Не-не, так нельзя. Это очень разные функции. Этому меня еще хаскель научил.

А что в хаскеле уже появилась перегрузка функций?

D>Не вижу здесь ограничений. У них трудно определить монадный трансформер. Это действительно ограничение. А в остальном, все очень логично.

Я имел в виду ограничения компилятора из-за которых приходится заниматься всякой фигней типа введения новых ключевых слов.

D>И я не представляю как одно можно было бы выразить через другое в общем случае... И то, и другое — must have однозначно.

Уффф....
module ListHelper
{
  public Yield[A](l : List[A], value : A) : void
  {
    l.Add(value);
  }

  public Yield[A](l : List[A], values : IEnumerable[A]) : void
  {
    l.AddRange(values);
  }
}

yield $x      =>  <[ ListHelper.Yield($(acc : Name), ($x)) ]>

.NET такие функции спокойно инлайнит.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 14:18
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Послал тебе вчера со своего гуглового аккаунта.


Что-то я его не получил. Слал на vc@rsdn.ru?

D>Поучаствовать не против. Например, я мог бы заменить то, что есть сейчас в каталоге snippets/ComputationExpressions. Там сейчас лежит только набросок.


Да, давай. Когда дойдет до приличного состояния можно будет в стандартную библиотеку макросов переместить.

D>Да, видел. Похоже на хаскелевский list comprehension.


Так с него и драли, как я понимаю.

D>Кстати, у них нотация do есть обобщение list comprehension.


Разве? По-моему там мало общего. Разве что оператор "<-".

D>Сейчас есть зависимость от самой сборки ComputationExpressions.dll. Это из-за вспомогательного класса EnumerableHelper. Потом его вынесу в отдельную dll. Будет маленький и независимый ComputationExpression.Runtime.dll.


Лучше ComputationExpression.dll и ComputationExpression.Macro.dll.
А в дальнейшем можно будет это дело перенести в Nemerle.dll и Nemerle.Macro.dll соответственно.

D>>>Можно использовать и yieldcomp. Тогда будет подставляться вся подпоследовательность.


VD>>Вот тут я разницу не уловил.


D>Иногда yieldcomp — очень полезная штука. Как и returncomp (aka return! в F#). С точки зрения монады yieldcomp и returncomp очень близки.


Кстати, а foreach в этих компрешеншонах поддерживается?

Лично я for и while использую крайне редко, а вот foreach очень часто.
ереписывается в чистые циклы.

D>Я думаю, что такая же эффективность. Эффективнее просто быть не может. Макрос comp практически не создает ничего лишнего в случае list comprehension. Только работа с аккумулятором в тех местах, где прописан yield и yieldcomp.


Он приводит к выделению объектов в куче и косвенным вызовам.

D>Сначала все складывается в обратном порядке, а потом в конце вызывается Rev ().


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

Ну, да не важно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 14:27
Оценка:
Здравствуйте, dsorokin, Вы писали:

WH>>Меняй.


D>OK. Как будет доступ.


Еще раз повторюсь, что мыла от тебя с экаунтом не получил.

Если проблемы с мылом, то можно послать через наш сайт или передать по скайпу (VladD2) или MSN (тоже VladD2).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 14:33
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>К тому же, так сделано в F# Должен сказать, что Дон Сайм очень хорошо все придумал и обдумал детали. Удивительно просто.


На самом деле — это главное в крутой макре — наличие хорошо продуманной идеи. Если она есть, то реализация уже является инженерной задачей. А вот если ее нет, то исследовательской.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 14:34
Оценка:
Здравствуйте, WolfHound, Вы писали:

D>>Должен сказать, что Дон Сайм очень хорошо все придумал и обдумал детали. Удивительно просто.

WH>Просто для кого? Лично я не хочу видеть кучу ключевых слов которых может и не быть.

+1

Предлагаю сделать очень просто. dsorokin зальет свою реализацию, а ты ее причешишь (если не вылезет каких-то дополнительных проблем).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 14:40
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>что в хаскеле уже появилась перегрузка функций?


В том то и дело, что разные функции должны называться по разному. Принципиальная позиция. Yield и YieldComp — две разные функции. Yield : A -> M[A]. YieldComp : M[A] -> M[A]. А вообще, в хаскеле есть классы типов (type classes). Отчасти заменяют перегрузку. Так сказать, правильная перегрузка.

WH>Я имел в виду ограничения компилятора из-за которых приходится заниматься всякой фигней типа введения новых ключевых слов.


Думаю, что это здесь ни причем. По моему эти новые ключевые слова нужны, потому что того требует задача. К тому же это значительно упрощает написание макроса comp. Трансляция кода получается однозначной и независимой ни от конкретных типов, ни от билдеров, что само себе дорогого стоит.
Re[13]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 14:42
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Предлагаю сделать очень просто. dsorokin зальет свою реализацию, а ты ее причешишь (если не вылезет каких-то дополнительных проблем).


Если мой голос что-то значит, то я резко против объединения Yield и YieldComp. Также Return и ReturnComp должны быть разными.
Re[13]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 14:43
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>У них трудно определить монадный трансформер. Это действительно ограничение. А в остальном, все очень логично.


А в чем трудность?

WH>>Просто для кого? Лично я не хочу видеть кучу ключевых слов которых может и не быть.


D>Можно просто не определять и не использовать ReturnComp и YieldComp в случае чего. Это факультативно.


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

Возможно ты не учитываешь различие в языках. У Немерла локальный, но более мощный вывод типов. Он позволяет разруливать сложные перегрузки (хотя это может серьезно тормозить, так что нужно быть аккуратным). Этим, иногда, можно воспользоваться.

D>А необходимость их следует хотя бы из array comprehension, для которого


D>
D>yield $x      =>  $(acc : Name).Add ($x)
D>yieldcomp $x  =>  $(acc : Name).AddRange ($x)
D>


D>И я не представляю как одно можно было бы выразить через другое в общем случае... И то, и другое — must have однозначно.


Как раз через перегрузку. Если создать два варианта перегруженных методов:

ListAddHelper[T](ary : List[T], elem : T) { ... }
ListAddHelper[T](ary : List[T], elems : IEnumerable[T]) { ... }

...

| yield $x      =>  ListAddHelper($(acc : Name), $x)
| yieldcomp $x  =>  ListAddHelper($(acc : Name), $x)

а компилятор на стадии типизации сам подставит нужную функцию.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 14:48
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>А главное, что YieldComp и ReturnComp обозначают, что в таком то месте есть монада. Это влияет на генерацию кода в целом. И не нужны типы. Все уже просчитано до нас


До нас оно было просчитано для языков с выводом типов по алгоритму Хиндли-Милера (модифицированному, конечно, но все же).

Так что Вольфхаунд тут может быть и прав.

В нашем распоряжении есть перегрузка, более мощный вывод типов и явное использование отложенной типизации. У авторов Хаскеля и F# всего этого не было и они ориентировались на возможности и особенности своих языков. Это могло серьезно повлиять на принимаемые решения и выбираемые подходы.

Так что я бы действительно подумал нельзя ли воспользоваться имеющимися преимуществами.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 14:53
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>В том то и дело, что разные функции должны называться по разному. Принципиальная позиция. Yield и YieldComp — две разные функции. Yield : A -> M[A]. YieldComp : M[A] -> M[A]. А вообще, в хаскеле есть классы типов (type classes). Отчасти заменяют перегрузку. Так сказать, правильная перегрузка.


Что есть классы типов — это философский вопрос. На мой взгляд они больше на интерфейсы похожи.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 14:57
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Если мой голос что-то значит, то я резко против объединения Yield и YieldComp. Также Return и ReturnComp должны быть разными.


Голос того кто что-то делает своими руками на благо общества значит почти все. Но и к другим голосам прислушиваться стоит.

Как я понимаю речь идет не об отказе от понятия, а об отказе от введения ключевых слов в пользу перегрузки. Если это возможно и не приведет к проблемам, то почему бы и нет? А yield можно просто назвать с большой буквы (Yield). Или даже YieldComp. Вопрос будет ли это оператором или функцией в определяемом пользователем классе.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 14:59
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Что-то я его не получил. Слал на vc@rsdn.ru?


Странно. Письмо ушло в 21:54. Может быть, из аттача его зарубили? Мог и гугл запросто, через который уходило... Мой email: david тчк sorokin собака гмыло дот ком.

D>>Кстати, у них нотация do есть обобщение list comprehension.


VD>Разве? По-моему там мало общего. Разве что оператор "<-".


Эта стрелка и есть монадический bind. Можно тот же list comprehension записать в нотации do, поскольку список — это монада. Отличий будет мало. Только с предикатами немного по другому выйдет. Видимо, отсюда все и пошло.

VD>Лучше ComputationExpression.dll и ComputationExpression.Macro.dll.

VD>А в дальнейшем можно будет это дело перенести в Nemerle.dll и Nemerle.Macro.dll соответственно.

Так и сделаю. Только по-моему лучше s добавить на конце.

VD>Кстати, а foreach в этих компрешеншонах поддерживается?


Пока нет. Но это только вопрос времени. Но придется повозится с обычным for. Foreach поддерживать легче, но там лучше сразу ориентироваться на типизированный IEnumerable[T].

D>>Я думаю, что такая же эффективность. Эффективнее просто быть не может. Макрос comp практически не создает ничего лишнего в случае list comprehension. Только работа с аккумулятором в тех местах, где прописан yield и yieldcomp.


VD>Он приводит к выделению объектов в куче и косвенным вызовам.


Ну, тогда при желании можно оптимизировать. Для list и array comprehension трансляция почти не затрагивает исходный код. Лишь обрабатываются yield, yieldcomp, да еще пустой () местами вставляется (там, где выражение обязано заканчиваться монадой).
Re[14]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 15:14
Оценка:
Здравствуйте, VladD2, Вы писали:

D>>У них трудно определить монадный трансформер. Это действительно ограничение. А в остальном, все очень логично.


VD>А в чем трудность?


В том, что один из билдеров (параметр монадного трансформера) является переменным. Наверное, здесь нужны макросы. Или классы типов.

VD>Возможно ты не учитываешь различие в языках. У Немерла локальный, но более мощный вывод типов. Он позволяет разруливать сложные перегрузки (хотя это может серьезно тормозить, так что нужно быть аккуратным). Этим, иногда, можно воспользоваться.


Дело не в перегрузке и даже не в особенностях реализации. А в том, что yield и yieldcomp — принципиально разные функции. Называть их одинаково — это ошибка дизайна.
Re[15]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 15:26
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Как я понимаю речь идет не об отказе от понятия, а об отказе от введения ключевых слов в пользу перегрузки. Если это возможно и не приведет к проблемам, то почему бы и нет? А yield можно просто назвать с большой буквы (Yield). Или даже YieldComp. Вопрос будет ли это оператором или функцией в определяемом пользователем классе.


Проблемы будут в понимании. Как минимум, у меня. YieldComp подразумевает монаду, а Yield — обычное значение. Я думаю, что ограничения ML здесь ни причем. Это пример правильной постановки задачи на мой взгляд. Перегрузка таит в себе скрытые опасности.

Сейчас какие-нибудь действия нужны с моей стороны или достаточно того, что я предоставил свой email? Могу попробовать переслать через ваш сайт, если подскажете как. Skype и MSN не использую.
Re[10]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 15:54
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Если проблемы с мылом, то можно послать через наш сайт или передать по скайпу (VladD2) или MSN (тоже VladD2).


Письмо получил. Отослал два ответа. Одно с аттачем.
Re[16]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 16:45
Оценка:
Здравствуйте, dsorokin, Вы писали:


D>Проблемы будут в понимании. Как минимум, у меня. YieldComp подразумевает монаду, а Yield — обычное значение.


Те кто будет пользоваться всем этим скорее всего даже не будут задумываться над тем, что за всем этим стоят монады. Они будут воспринимать это как еще одну фичу.

D> Я думаю, что ограничения ML здесь ни причем. Это пример правильной постановки задачи на мой взгляд. Перегрузка таит в себе скрытые опасности.


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

D>Сейчас какие-нибудь действия нужны с моей стороны или достаточно того, что я предоставил свой email? Могу попробовать переслать через ваш сайт, если подскажете как. Skype и MSN не использую.


Я добавил тебя в комитеры (о чем написал по мылу). Так что можешь менять код.
Инструкция по генерации пароля и чекауту можно найти здесь:
http://code.google.com/p/nemerle/source/checkout
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 16:49
Оценка:
Здравствуйте, dsorokin, Вы писали:

VD>>Лучше ComputationExpression.dll и ComputationExpression.Macro.dll.

VD>>А в дальнейшем можно будет это дело перенести в Nemerle.dll и Nemerle.Macro.dll соответственно.

D>Так и сделаю. Только по-моему лучше s добавить на конце.


VD>>Кстати, а foreach в этих компрешеншонах поддерживается?


В смысле ComputationExpressions?
Добавь.

D>Foreach поддерживать легче, но там лучше сразу ориентироваться на типизированный IEnumerable[T].


Гы-гы. Ты наверно даже не понимаешь насколько ты ошибаешься. foreach в Немерле раз в 10 навороченее чем его аналог в C#. Он по полной программе поддерживает паттерн-матчинг.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 17:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Те кто будет пользоваться всем этим скорее всего даже не будут задумываться над тем, что за всем этим стоят монады. Они будут воспринимать это как еще одну фичу.


Согласен. Как и с linq
Re[10]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 21.04.10 17:13
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Гы-гы. Ты наверно даже не понимаешь насколько ты ошибаешься. foreach в Немерле раз в 10 навороченее чем его аналог в C#. Он по полной программе поддерживает паттерн-матчинг.


Паттерн-матчинг сохранится. foreach ($x in $coll) $body будет преобразован в случае монады в $builder.ForEach ($coll, $x => $body). При желании эту кодо-генерацию можно будет переопределить. Меня сейчас больше for беспокоит. Чтобы свести к while нужен $builder.Zero (), которого может и не быть. Придется сводить к $builder.ForEach, а для этого придется создавать коллекцию (через ленивый stream).
Re[11]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 17:51
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Здравствуйте, VladD2, Вы писали:


VD>>Гы-гы. Ты наверно даже не понимаешь насколько ты ошибаешься. foreach в Немерле раз в 10 навороченее чем его аналог в C#. Он по полной программе поддерживает паттерн-матчинг.


D>Паттерн-матчинг сохранится. foreach ($x in $coll) $body будет преобразован в случае монады в $builder.ForEach ($coll, $x => $body).


Погляди примеры использования foreach в этой статье
Автор(ы): Чистяков Влад (VladD2)
Дата: 03.03.2007
Язык программирования Nemerle заинтересовал многих в первую очередь своей мощнейшей подсистемой мак-росов. Однако и без них Nemerle предоставляет ряд су-щественных улучшений по сравнению с традиционными, императивными языками программирования (такими как Java, C# и C++).
Nemerle, кроме традиционного императивного програм-мирования, поддерживает функциональное программи-рование. Это выражается в наличии конструкций, упро-щающих манипуляцию функциями, построение и анализ сложных структур данных и т.п.
К сожалению, если вы не использовали возможности, присущие функциональным языкам ранее, то вам будет трудно оценить, насколько Nemerle может оказаться вам полезным в реальной повседневной работе. Данная статья призвана в неформальной форме продемонс-трировать это.
. Там есть забавные примеры:
foreach (method is IMethod when method.IsPublic in typeMembers)
  processMethod(method);

...

def expressions = [Literal(1.23), Mul(Literal(2), Literal(3))];
foreach (expr in expressions)
{
  | Mul(e1, e2) => WriteLine($"$(expr.Eval()) = $e1 * $e2");
  | Div(e1, e2) => WriteLine($"$(expr.Eval()) = $e1 * $e2");
  ...
}

у тебя он работать не будет.

Потом foreach раскрывается в эффективную реализацию в зависимости от типа аргумента.

И одно замечание!

В твоем случае для описния лябды лучше использовать не синтаксис "$x => $body", а синтаксис "fun(x) { $body }".
Дело в том, что первый вариант (использованный тобой) — это тоже макрос. И я не гарантирую, что он учитывает все случае поддержки паттерн-матчинга которые реализованы в реальной лямбде. Это все же облегченный синтаксис.

D> При желании эту кодо-генерацию можно будет переопределить. Меня сейчас больше for беспокоит. Чтобы свести к while нужен $builder.Zero (), которого может и не быть. Придется сводить к $builder.ForEach, а для этого придется создавать коллекцию (через ленивый stream).


Ну, напиши ты ForEach через yield. Будет тебе ленивый ForEach.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: Как определить принадлежность генерику?
От: Аноним  
Дата: 21.04.10 18:27
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Согласен. Как и с linq


В LINQ есть функции Select и SelectMany, которые отличаются подобным образом. Может, лучше в традициях линка оставить названия Yield и YieldMany?
Re[11]: Как определить принадлежность генерику?
От: hardcase Пират http://nemerle.org
Дата: 21.04.10 18:58
Оценка: +1
Здравствуйте, dsorokin, Вы писали:

D>Здравствуйте, VladD2, Вы писали:


VD>>Гы-гы. Ты наверно даже не понимаешь насколько ты ошибаешься. foreach в Немерле раз в 10 навороченее чем его аналог в C#. Он по полной программе поддерживает паттерн-матчинг.


D>Паттерн-матчинг сохранится. foreach ($x in $coll) $body будет преобразован в случае монады в $builder.ForEach ($coll, $x => $body). При желании эту кодо-генерацию можно будет переопределить. Меня сейчас больше for беспокоит. Чтобы свести к while нужен $builder.Zero (), которого может и не быть. Придется сводить к $builder.ForEach, а для этого придется создавать коллекцию (через ленивый stream).


А нужен ли for? Я, например, последний раз я его использовал когда тестировали скорость пузырьковых сортировок.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[12]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.10 19:44
Оценка:
Здравствуйте, hardcase, Вы писали:

H>А нужен ли for? Я, например, последний раз я его использовал когда тестировали скорость пузырьковых сортировок.


Для порядка конечно нужен. А так, да... Я тоже его практически не использую.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[19]: Как определить принадлежность генерику?
От: Ziaw Россия  
Дата: 22.04.10 01:21
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Здравствуйте, dsorokin, Вы писали:


D>>Согласен. Как и с linq


А>В LINQ есть функции Select и SelectMany, которые отличаются подобным образом. Может, лучше в традициях линка оставить названия Yield и YieldMany?


А может оставить Yield и YieldComp, но их будет заменять ключевое слово yield там где это возможно?
... << RSDN@Home 1.2.0 alpha 4 rev. 1468>>
Re[12]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 22.04.10 04:12
Оценка:
Здравствуйте, VladD2, Вы писали:

VD> Потом foreach раскрывается в эффективную реализацию в зависимости от типа аргумента.


Тогда можно сделать так:

foreach ($x in $coll) $body  

=>

$builder.ForEach ($coll, fun ($(var : Name)) {
  match ($(var : Name))
  {
    | $x => $body;
    | _ => ()
  }
})


VD> Ну, напиши ты ForEach через yield. Будет тебе ленивый ForEach.


Несовсем понятно как, да и эффективнее сделать через ленивый поток:

for (mutable $x = $init; $cond; $next) $body

=>

{
  mutable $x = $init;

  def $(loop : Name) ()
  {
    if ($cond == false)
      LazyStream.Nil ()
    else
      LazyStream.Cons ($x, 
        fun () { $next; $(loop : Name) () })
  }

  $builder.ForEach ($(loop : Name) ().ToEnumerable(), fun ($x) $body)
}
Re[20]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 22.04.10 04:28
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>А может оставить Yield и YieldComp, но их будет заменять ключевое слово yield там где это возможно?


Это еще хуже. Нужно разделение и на функции, и на ключевые слова. К тому же так работает макрос сейчас.
Re[19]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 22.04.10 04:31
Оценка:
Здравствуйте, Аноним, Вы писали:

А>В LINQ есть функции Select и SelectMany, которые отличаются подобным образом. Может, лучше в традициях линка оставить названия Yield и YieldMany?


Здесь свои традиции: def!, do!, return!, yield!, use!. Но с восклицательным знаком возникла проблема разбора. Да и лично мне нравится теперь этот comp на конце: def/defcomp, do/docomp, return/returncomp, yield/yieldcomp, using/usingcomp. Но это можно поменять.
Re[12]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 22.04.10 05:40
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Потом foreach раскрывается в эффективную реализацию в зависимости от типа аргумента.


В прошлый раз забыл о Zero. Здесь же монада:

foreach ($x in $coll) $body  

=>

$builder.ForEach ($coll, fun ($(var : Name)) {
  match ($(var : Name))
  {
    | $x => $body;
    | _ => $builder.Zero ()
  }
})


То есть добавляется еще одно требование. Либо без требования Zero, но и без мощного матчинга. Либо с требованием Zero, но и с развернутым матчингом. Дилемма. Может статься, что если определяется For, то и Zero как бы подразумевается сам собой (моноид). Надо поразмыслить.
Re[13]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.10 13:53
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Тогда можно сделать так:


D>
D>foreach ($x in $coll) $body  

D>=>

D>$builder.ForEach ($coll, fun ($(var : Name)) {
D>  match ($(var : Name))
D>  {
D>    | $x => $body;
D>    | _ => ()
D>  }
D>})
D>


Я же привел примеры. Посмотри внимательно второй пример. Там код получается сильно сложнее...

D>Несовсем понятно как, да и эффективнее сделать через ленивый поток:


Что там понимать то? Все элементарно:
public ForEachLazy[T](source : IEnumerable[T]) : IEnumerable[T]
{
  foreach (x in source)
    yeild x;
}

Далее применяем это дело к любому IEnumerable[T] и получаем ленивый вариант. Точнее он будет не совсем ленивым, так как при перезапуске будет возвращаться новый итератор. Но, как я понимаю, в данном случае разницы не будет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 22.04.10 15:44
Оценка:
Здравствуйте, VladD2, Вы писали:

VD> Я же привел примеры. Посмотри внимательно второй пример. Там код получается сильно сложнее...


Ну, да. Странность второго foreach сразу не разглядел. Подумаю над этим.

VD> Далее применяем это дело к любому IEnumerable[T] и получаем ленивый вариант. Точнее он будет не совсем ленивым, так как при перезапуске будет возвращаться новый итератор. Но, как я понимаю, в данном случае разницы не будет.


Гы. Зачем нужен ForEachLazy если есть уже source?.. Должно быть начало. И ленивый поток его дает. Я уже сделал for через foreach.

Кстати, необходимость Zero для foreach вытекает из простой вещи. Zero можно рассматривать как пустой цикл. Потому он должен быть.

Тут натолкнулся на неприятную вещь. Нельзя инстанцировать шаблон по типу void. Для монад это чертовски важно. Вопрос в том, будет ли это возможно в будущем, или это фича языка такая? Пока же создал поддельный тип ComputationVoid.

На сегодняшний момент состояние такое. Реализованы def, mutable, match, if, unless, when, while, do-while, foreach (с твоим замечанием — не умеет), for, repeat. Также монадические defcomp, return, returncomp, yield, yieldcomp и новые call, callcomp. Так я назвал аналоги do и do! из F#. Им как раз нужно инстанцирование по void. F# это умеет. Среди важных остались using, usingcomp и try. С первыми двумя придется повозиться.
Re[13]: Как определить принадлежность генерику?
От: Аноним  
Дата: 22.04.10 15:52
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>То есть добавляется еще одно требование. Либо без требования Zero, но и без мощного матчинга. Либо с требованием Zero, но и с развернутым матчингом. Дилемма. Может статься, что если определяется For, то и Zero как бы подразумевается сам собой (моноид). Надо поразмыслить.


Zero = default(T) ?
Re[14]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 22.04.10 16:11
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Zero = default(T) ?


Нет, это нуль относительно операции Combine (монадический then).

Кстати, результаты залил в svn в каталог snippets/ComputationExpressions. Там нет комментариев. Еще нет using, usingcomp и try.
Re[15]: Как определить принадлежность генерику?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.10 20:22
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Гы. Зачем нужен ForEachLazy если есть уже source?.. Должно быть начало. И ленивый поток его дает. Я уже сделал for через foreach.


Да, это я что-то ступил. Надо больше отдыхать .

Что же до твоего LazyStram, но во-первых напрягает его название. Это все же списко, а не поток.
А во-вторых в немерле есть макра для более элегантной реализации того же самого — макра Nemerle.lazy и тип LazyValue.
Вот погляди реализацию аналога твоего LazyStram:
LazyList.n

D>Кстати, необходимость Zero для foreach вытекает из простой вещи. Zero можно рассматривать как пустой цикл. Потому он должен быть.


Ну, должен так должен.

D>Тут натолкнулся на неприятную вещь. Нельзя инстанцировать шаблон по типу void. Для монад это чертовски важно. Вопрос в том, будет ли это возможно в будущем, или это фича языка такая? Пока же создал поддельный тип ComputationVoid.


А нельзя просто перегрузкой обойтись? Во всех остальных случаях ею обходились.

D>На сегодняшний момент состояние такое. Реализованы def, mutable, match, if, unless, when, while, do-while, foreach (с твоим замечанием — не умеет), for, repeat. Также монадические defcomp, return, returncomp, yield, yieldcomp и новые call, callcomp. Так я назвал аналоги do и do! из F#. Им как раз нужно инстанцирование по void. F# это умеет. Среди важных остались using, usingcomp и try. С первыми двумя придется повозиться.


Поглядел... Примеров не хватает. Точнее они есть, но как-то они сумбурно организованы.

Хотелось бы чтобы можно было поглядеть на простые и понятные реализации и их применения.

Ну, и было бы здорово если бы про это все написать статейку. За одно и документация получилась бы!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: Как определить принадлежность генерику?
От: dsorokin Россия  
Дата: 23.04.10 04:09
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Что же до твоего LazyStram, но во-первых напрягает его название. Это все же списко, а не поток.

VD>А во-вторых в немерле есть макра для более элегантной реализации того же самого — макра Nemerle.lazy и тип LazyValue.
VD>Вот погляди реализацию аналога твоего LazyStram:
VD>LazyList.n

Нет, это нормальное название. Даже приставка Lazy лишняя. Такое название используется в хаскеле и SICP (Structure and Interpretation of Computer Programs). А так, твой пример — близнец, но такого класса нет в Nemerle.dll, и он не умеет превращаться в IEnumerable[T].

D>>Тут натолкнулся на неприятную вещь. Нельзя инстанцировать шаблон по типу void. Для монад это чертовски важно. Вопрос в том, будет ли это возможно в будущем, или это фича языка такая? Пока же создал поддельный тип ComputationVoid.


VD>А нельзя просто перегрузкой обойтись? Во всех остальных случаях ею обходились.


Увы, нельзя. Нужно создавать значения типа M[void], которые обозначают некие вычисления, которые во время своего выполнения производят некоторый побочный эффект. Это особенно будет заметно, если кто-нибудь создаст аналог async из F#.

VD>Поглядел... Примеров не хватает. Точнее они есть, но как-то они сумбурно организованы.


Да, сейчас примеры так себе для целей демонстрации. Я на них проверяю генерацию кода. Снимаю комментарий в файле CompMacro.n и смотрю, что там создается.

VD>Ну, и было бы здорово если бы про это все написать статейку. За одно и документация получилась бы!


Согласен. Постараюсь найти время.

Кстати, сейчас такая вещь. Синтаксис list/array/enumerable comprehension пересекается с синтаксисом в общем случае. Из-за этого важен порядок объявлений:

using Nemerle.ComputationExpressions;
using Nemerle.ComputationExpressions.Extensions;


Если две строки поменять местами, то парсер начинает ругаться. Знаю, что нехорошо. Может быть, поменять синтаксис для comprehension? Но хотелось бы сохранить простоту и единообразие.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.