Re: Ликбез по ComputationExpressions
От: dsorokin Россия  
Дата: 23.04.10 07:08
Оценка: 111 (3)
Здравствуйте, hardcase, Вы писали:

H>какие задачи решает эта система макросов, для чего она нужна?


Последние новости. Сейчас работаю над хвостовой оптимизацией для enumerable comprehension (пока на залили в svn). Возможны финты типа:

    def stream (n)
    {
      comp enumerable
      {
        yield n;
        yieldcomp (stream (n + 1));
      }
    }


Кстати, работает быстрее, чем аналогичная вещь на F# Вообще, еnumerable comprehension создает ленивую последовательность, которая вычисляется только по требованию. Иногда незаменимая вещь.

Вот, более полезный пример. Лениво возвращает список всех файлов, включая вложенные, из заданного каталога.

    
    def filesUnderFolder (rootFolder : string) : IEnumerable [string]
    {
      comp enumerable
      {
        foreach (file in System.IO.Directory.GetFiles (rootFolder))
          yield file;
        foreach (dir in System.IO.Directory.GetDirectories (rootFolder))
          yieldcomp (filesUnderFolder (dir))
      }
    }
Re[2]: Ликбез по ComputationExpressions
От: WolfHound  
Дата: 23.04.10 10:01
Оценка: 39 (1) +1
Здравствуйте, dsorokin, Вы писали:

Несколько замечаний по коду:

  1. Начинай сообщение для коммита со строки:

    [Snippets] Computation Expressions

    Чтобы было проще понимать что да коммит.


  2. Не экономь на файлах.
    Лучше много маленьких чем мало больших.
    Ибо так гораздо удобнее искать что где лежит.


  3. EmptyEnumerable[T]/EmptyEnumerator[T] не имеют состояния. Следовательно их можно раз и на всегда закешировать в статической переменной.


  4. Зачем так сложно?
      public module EnumerableHelper
      {
    ...    
        public Delay[T] (cont : void -> IEnumerable[T]) : IEnumerable[T]
        {
          foreach (t in cont ())  yield t
        }


    Почему не:
        public Delay[T] (cont : void -> IEnumerable[T]) : IEnumerable[T]
        {
          cont ();
        }



  5. Тут ты тоже перемудрил. Так лучше:
      public variant LazyStream[T]
      {
        | Nil;
        | Cons { value : T; cont : void -> LazyStream[T] }
        
        public ToEnumerable () : IEnumerable[T]
        {
          def loop(_)
          {
            | Nil => ()
            | Cons (value, cont) =>
              yield value;
              loop(cont());
          }
          loop(this);
        }
      }



  6. Вместо:
          def temp = Macros.NewSymbol ();
          def loop = Macros.NewSymbol ();

    лучше писать
          def temp = Macros.NewSymbol ("temp");
          def loop = Macros.NewSymbol ("loop");

    Так макрос после рускрутки получится более читаемый.


  7. Тут происходит нечто страшное:
          def coll =
            <[
                EnumerableHelper.Delay (() =>
                  {
                    $init;
                    $postInit;
                    
                    def $(loop : name) ()
                    {
                      match ($cond)
                      {
                        | false => LazyStream.Nil ();
                        | true =>  LazyStream.Cons ($var, () => { $change; $(loop : name) () })
                      }
                    }
                    
                    $(loop : name) ().ToEnumerable ()
                  })
            ]>;

    def $(loop : name) () лишнее.
    Достаточно def loop ()
    Ибо макросы по умолчанию гигееничны.

    Но главное тут плодится куча мусора на ровном месте.
    Вот так гораздо лучше:
      public module ForHelper
      {
        public Enumerate[T](cond : void -> bool, value : void -> T, change : void -> void) : IEnumerable[T]
        {
          while (cond())
          {
            yield value();
            change();
          }
        }
      }

          def coll =
            <[
                EnumerableHelper.Delay (() =>
                  {
                    $init;
                    $postInit;
                    
                    ForHelper.Enumerate(() => $cond, () => $var, () => $change)
                  })
            ]>;



  8. Тут ИМХО лучше так:
      internal class ListBuilder : ComputationBuilder
    ...
        public override Yield (expr : PExpr) : PExpr
        {
          <[ $(acc : name).Add($expr) ]>
        }
    ...
        public override Run (expr : PExpr) : PExpr
        {
          <[
            { 
              mutable $(acc : name) = List();
              $expr;
              $(acc : name).NToList ()
            }
          ]>
        }


  9. Зачем нужно два void'а?
      public sealed class ComputationVoid
      {
        public static Value : ComputationVoid = ComputationVoid ()
      }
    
      public variant FakeVoid
      {
        | FakeVoid
      }



  10. Можно писать так:
    _testDo(10).Iter(WriteLine);

    местный вывод типов может даже в таких ситуациях разбираться...


  11. А еще я вернул ComputationExpressions.sln который ты зачемто удалил.
    Ибо многим работать в IDE банально удобнее.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: Ликбез по ComputationExpressions
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 28.04.10 15:14
Оценка: 12 (2)
Здравствуйте, VladD2, Вы писали:

Сорри за неоперативность, времени не было ответить! И ещё раз сорри — получилось длинно.

VD>Какие люди в нашей деревне!

VD>Привет!

Я иногда читаю этот форум, тут пишут много интересного

L>>...Так вот, монада — это моноид над функторами. Всё. Моноид над функторами.

VD>Проблема в том, что в языках которые мы тут обсуждаем (Немерле и возможно Шарп) просто нет понятий "функтор". Так что их пользователям твои рассказы просто разрывают мозг. Пусть те кто считает себя C#-программистом и кому эти рассказы не рвут мозг кинет в меня камень (путем установки минуса, плиз, а не явно).

Упс. Я действительно думал, что функтор (он же отображение — map) — вещь, хорошо знакомая.

L>>Есть ассоциативная операция над списками (конкатенация), значит список — монада.

VD>Значит если мы не добавим с наш список SelectMany, то мы имеем дел с простым списком?

Если у этого списка нет операций map и concat, то да. Тут прикол в чём. Монада — это не тип данных, это операции над типом данных. Проще объяснить, наверное на моноиде (ассоциативная операция). Вот есть тип "целое число". Моноидом над ним будет операция сложения. Или операция умножения. Или сумма по модулю N. Т.е. тип не определяет какие операции будут над ним производиться. Это операции могут быть ассоциативными или нет.

L>>Есть ассоциативная операция над императивом (точка с запятой из сишных языков) — значит императив — монада.

VD>А если язык не ленивый по умолчанию, и точка запятой и так позволяет выполнить два выражения последовательно?

К сожалению, как только мы начинаем говорить о таких языках, то видим, что действия (statements) у него не first-class values. А значит смысла говорить о (a;b);c ~ a;(b;c) нет, т.к. скобки определены только над выражениями (expressions). Во-вторых, действия в таких языках не есть функтор. Мы не можем взять какое-то действие и отобразить его в другое. Т.е. дело тут не в ленивости. В конце-концов делают же монады на неленивых языках.

L>> Есть ассоциативная операция над продолжением (последующий вызов), значит продолжения — монада.

VD>А можно так: Есть передача в качестве параметра функции которая продолжит вычисление, значит монада — это продолжение?

Да. Но тут такой момент. bind — сложная операция для понимания. Гораздо проще грокнуть именно join — это и есть ассоциативная операция. А уж одно через другое выражается легко.

Вот, что такое продолжение? По сути, это функция, которая принимает функцию (функция-параметр) и ей передаёт некий результат своего вычисления, а возвращает уже результат применения этой функции-параметра. И вот тут важно увидеть, что продолжение оборачивает то по сути своё возвращаемое значение, а не результат функции-параметра.
type Cont[R,A] = Fun[Fun[A,R],R]

Ну пусть класс эту функцию оборачивает, например.
class Cont[R,A] {
    cont: Fun[Fun[A,R],R];
    Cont(cont: Fun[Fun[A,R],R]) { this.cont = cont; }
}

Fun<A,R> — это функция с параметром типа A и результатом типа R.

Можем мы над ней определить отображение (Map, функтор)? Во-первых, что на что мы будем отображать? Т.к. мы выяснили, что продолжение оборачивает своё возвращаемое значение, значит сигнатура будет такой
class Cont[R,A] {
    Map[B](fun: Fun[A,B]): Cont[R,B] { ... }
}

Вывести его тело легко (оно выводится автоматически, на самом деле — Carry-Howard в действии)
class Cont[R,A] {
    Map[B](fun: Fun[A,B]): Cont[R,B] {
        return new Cont(k => this.cont(x => k(fun(x))));
    }
}

Итак! Мы поимели функтор! Теперь нам надо определить ассоциативную операцию, для связывания продолжений в цепочку (иначе нафиг они нам сдались!). Не зная о монадах сделать это как минимум тяжело. Зная — тоже тяжело Но нам поможет знание одной очень полезной штуки.

Оказывается, что над монадами проще определять не Bind, а Join, а уже через него Bind выражается очень легко. Join — это операция с типом
Join(m: Cont[Cont[A]]): Cont[A]

т.е. уплощяем (flat) некий функтор. Bind через Join определяется так:
cont.Bind(f) == Join(cont.Map(f))

Немного математики (нет необходимости читать): Join как раз и выражает моноид над функтором, который мы определили выше. Вспоминаем: моноид — это ассоциативная операция. функтор — (утрировано) тип, оборачивающий некий тип. Моноид над функторами будет операцией над типами. Т.е. есть функтор SomeFunctor[T], есть операция TypeMonoid[F] ~ F[F[T]]. Тут можно увидеть, что Join и представляет такую операцию.

Вернёмся к продолжениям. Join должен брать продолжение, определённое над продолжением (!) над неким значением и возвращать продолжение над этим значением. Я сразу напишу тип и реализацию. Могу где и налажать, особенно с синтаксисом. т.к. не знаком.
class Cont[R,A] {
    static Join[R,A](c: Cont[R,Cont[R,A]]): Cont[R,A] {
        return new Cont(x => c.cont(k => k.cont(x)));
    }
}

Ну тут из типа видно, что мы хотим сделать. Смысл простой, мы flat-им продолжение, превращая его в понятное. Вот так, лёгким движением руки, зная о монадах и выведя тип самого Cont, мы получили продолжения, с которыми можем работать в общем для монад стиле — связывая их в цепочку.

VD>Или тут важна ассоциативность?


Да. Ассоциативность над функторами. Т.е. определяем две операции (на самом деле три, но третья — return уж очень простая) — отображение (функтор) и какую-нибудь ассоциативную операцию над этим функтором — это и есть монада, а не сам тип.

L>>Т.к. функторов везде полно (большинство типов T<A> являются функторами — как контейнеры, так и оболочки над функциями) и т.к. ассоциативных операций ещё больше, то неудивительно, что мы постоянно натыкаемся на монады.


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


Увы, ты прав, после того, что я написал выше, я понял, что не всё так просто, бэкграунд действительно нужен. Но совсем небольшой.

VD>Мне кажется, что монады есть только там где а) есть факт связи двух вычислений по средствам функций, б) человек использующий это дело понимает что пользуется именно этим инструментом, а не отталкивается от какой-то другой теории (например, что он тупо выпрямляет дерево или вложенные списки в плоский список). Согласен?


а) есть жёсткое определение — имеем функтор (т.е. операцию Map), имеем ассоциативную операцию над ним (Join) — всё, есть монада. То что ты написал — скорее следствие, не всегда верное. Пример, есть два вычисления (1 + 2) и (3 + 4) мы связываем их посредством функции (+) — это монада? Нет. С другой стороны — дерево мы можем отобразить на дерево, сохранив структуру; из дерева деревьев можем сделать дерево значений, значит это монада.

б) "Слышен ли звук падения дерева в лесу, в котором нет наблюдателя?". Наверное, согласен, нет смысла от того, что там есть монада. Но мы так до философии математики доберёмся

L>>Попытка удалась?

VD>Ну, как сказать. Разглядеть монаду (при желании) в SelectMany я мог и раньше. Точнее разглядеть я мог сигнатуру бинда. Но вот убей меня я не могу понять зачем приплетать монады туда где от их (логического) использования нет никакого смысла.

Если нет пользы, то приплетать не надо! Я то говорю о пользе. На удивление такой ну совершенно абстрактный инструмент оказался очень практичным. Монада хорошо ложится на list/query/monad comprehension ().

for y in x for z in y if z > 0 select sin(z)
это выражение похожее на определение множества
{ sin(z) | y &isin; x ; z &isin; y ; z > 0 }
замечательно обобщается до монадического bind, на котором и строится linq.

Зная законы монад/функторов ты можешь формальнее (а значит, корректнее) рассуждать о любой кошерной реализации linq.

Замены (equational reasoning — один из самых полезных инструментов практика, любой нормальный рефакторинг строится на нём)
from x in xs select x на xs.
from x in xs select f(x) на xs.Map(x).
from x in xs from y in foo(x) select y на xs.SelectMany(foo)
и т.д.

Задействовать свои комбинаторы, которые работают для любых реализаций linq (абстракция!) например
Map2, Map3 — схожий с обычным Map, но для нескольких контейнеров
from x in xs from y in ys select foo(x,y) на Map2(xs, ys)(foo)
Тот же Join, который оказывается полезным в самых неожиданных местах.

Зная о монадах мы можем предположить, что проблема, для которой мы сейчас ищем решение может быть решена в рамках linq

А это (нагло цитирую Last Cjow Rhrr и себя)

Продолжения
Обработка исключений
ГУИ
Логгинг
Коммуникации между процессами
Парсеры
Интерпретаторы
Энергичное исполнение кода
Интерфейс к коду на других языках (FFI)

Бэктрекинг
Логика
STM
Multiresult
optional result
случайные значения
недетерминированность

да и самому можно толпу придумать — например, упорядочивание результатов, или для моделирования устройств — вычисления с тактами, ну и т.д.


Многое из этого не нужно в рамках C#, но что-то ведь может и пригодится. Если какое-то знание позволит тебе увидеть одно из решений, возможно лучшее, то зачем лишать себя его?

VD>В прочем, с философской точки зрения попытка хорошая. Просто мы совершенно разные люди. Тебе видимо чужд не научный метод определения пола кошаков (бросил... побежала — кошка, побежал — кот) .


Честно говоря, я просто вижу как много практичности в математике и как она помогает мне писать программы. Я стал по другому подходить к решению задач, стал лучше рассуждать о коде. Ну, или мне так кажется

VD>ЗЫ

VD>Кстати, ты как специаилст в области монад и другой нечисти, не мог бы нам объяснить, что "мощнее" полноценное (не ограниченное) продолжение или монада.

VD>Ну, в смысле отвата на два вопроса:

VD>1. Можно ли выразить любую монаду продолжением?

Интуитивно не вижу к этому препятствий, как-то в "Декларативном Программировании" мы с palm_mute шалили
Автор: lomeo
Дата: 27.11.07
. Смотри — на продолжениях можно сделать ветвление, можно сделать цикл, значит они тьюринг-полны

VD>2. Можно ли выразить любое продолжение монадой?


На продолжение можно посмотреть как на монаду, определив над ней Map и Join (выше мы это проделали).

P.S. Математика рулит, честно
Re[2]: Ликбез по ComputationExpressions
От: WolfHound  
Дата: 25.04.10 22:54
Оценка: 37 (1)
Здравствуйте, dsorokin, Вы писали:

D>В общем, считайте, что async из F# уже почти есть в Немерле

Почитал про async из F#.
Что-то он мне не нравится.

1)Вот кто им сказал что всем хватит одного пула потоков?

2)Использование SynchronizationContext.Current диверсия. В прочем SynchronizationContext сам по себе не нужен.

Вместо этих двух уродств. Нужно сделать ExecutionContext который может быть одним из нескольких пулов потоков, очередью разбора собщений WindowsForms или чемто еще.

Тогда можно будет делать так:
    def poolContext = ThreadPoolExecutionContext(10);
    def guiContext = WindowsFormsExecutionContext(form);
    
    def worker()
    {
        comp async
        {
            callcomp Async.SwitchTo(poolContext);
            //делаем что-то тяжолое в контексте пула.
            callcomp Async.SwitchTo(guiContext);
            //а тут спокойно ковыряемся в gui.
            returncomp worker();
        }
    }
    poolContext.Start(worker());


3)Async.Sleep использование int когда есть TimeSpan диверсия.

4)Агенты слишком куцое решение.
По хорошему нужно сделать каналы.
А на каналах агенты делаются одной левой.
Причем можно сделать весьма навороченные как в сингулярити.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[17]: Ликбез по ComputationExpressions
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.04.10 13:23
Оценка: 5 (1)
Здравствуйте, dsorokin, Вы писали:

D>А можно подробнее? Ellipsis имеет один параметр body. Сейчас этот body у меня преобразовывается в поисках монады. Мне интересно знать, насколько это корректно. Можно этот Ellipsis создать в коде?


Куда же подробнее? Это заглушка для квази-цитирования. Может появляться только внутри цитат. Нужно для генерации кода вхождения путем подстановки спласа.

Самому еще не разу не приходилось генерировать обработчики catch-ей, но это должно выгдядеть как-то так:
<[
try
{
}
catch 
{
  ..$(GenerateExcetpionHandlers())
}
]>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Ликбез по ComputationExpressions
От: WolfHound  
Дата: 23.04.10 10:54
Оценка: 1 (1)
Здравствуйте, dsorokin, Вы писали:

D>Так делать нельзя. Теряется смысл в Delay. Потом, я написал отдельный DelayedEnumerable[T] : IEnumerable[T]. Через него будет эффективнее.

А... кажется понял в чем прикол.

D>На мой взгляд разницы большой нет. Но соглашусь, что так проще понять.

Так не только проще понять но еще и эффективнее.

D>Просто у меня нет полноценной студии. Есть VS C# Express 2005 и VS 2008 Shell. Не знаю, можно ли к ним прикрутить интеграцию?

Есть NemerleStudio. http://www.rsdn.ru/forum/prj.nemerle/2878763.1.aspx
Автор: Блудов Павел
Дата: 18.03.08

Инсталятор немерла брать ессно свежий.
Есдинственная проблема это то что NemerleStudio хочет расширение nsln вместо sln. Просто переименуй файл.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: Ликбез по ComputationExpressions
От: WolfHound  
Дата: 24.04.10 16:14
Оценка: +1
Здравствуйте, dsorokin, Вы писали:

D>Интересная идея. Наверное, можно как-то связать с написанием своих собственных DSL. Следующий уровень после вычислительных выражений.

Упрощение создания собственных DSL это вообще отдельная история.
Причем для следующей версии языка.
Ибо для этого придется переделать все. От парсера до вывода типов.

D>Сейчас предлагаю завершить текущую схему. Я добавил более полную реализацию foreach (с матчингом и приведением :>) и блок try-finally. Из основных остались try-catch и using/usingcomp.

Делай как знаешь.
Я просто опытом делюсь.
Мне при работе над ПЕГом модель очень сильно помогла.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Ликбез по ComputationExpressions
От: hardcase Пират http://nemerle.org
Дата: 22.04.10 19:43
Оценка:
Недавно было обсуждение сабжа
Автор: dsorokin
Дата: 17.04.10
. Так вот, не могли бы сведущие в предмете (ComputationExpressions) объяснить таким танкистам, как я, какие задачи решает эта система макросов, для чего она нужна?
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Ликбез по ComputationExpressions
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.10 19:55
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Недавно было обсуждение сабжа
Автор: dsorokin
Дата: 17.04.10
. Так вот, не могли бы сведущие в предмете (ComputationExpressions) объяснить таким танкистам, как я, какие задачи решает эта система макросов, для чего она нужна?


Главное ее предназначение — доказательство того, что язык с макросами на которых можно реализовать некоторую фичу мощнее чем язык в который встроили такую фичу.

Ну, а если серьезно, то это реализация одной фичи из F# и (от части) Haskell-я:
http://en.wikibooks.org/wiki/F_Sharp_Programming/Computation_Expressions
http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc257733552
http://msdn.microsoft.com/en-us/library/dd233182.aspx
http://langexplr.blogspot.com/2008/10/using-f-computation-expressions-to-read.html
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Ликбез по ComputationExpressions
От: hardcase Пират http://nemerle.org
Дата: 22.04.10 20:00
Оценка:
Здравствуйте, VladD2, Вы писали:

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


H>>Недавно было обсуждение сабжа
Автор: dsorokin
Дата: 17.04.10
. Так вот, не могли бы сведущие в предмете (ComputationExpressions) объяснить таким танкистам, как я, какие задачи решает эта система макросов, для чего она нужна?


VD>Главное ее предназначение — доказательство того, что язык с макросами на которых можно реализовать некоторую фичу мощнее чем язык в который встроили такую фичу.


Мило.

VD>Ну, а если серьезно, то это реализация одной фичи из F# и (от части) Haskell-я:

VD>http://en.wikibooks.org/wiki/F_Sharp_Programming/Computation_Expressions
VD>http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc257733552
VD>http://msdn.microsoft.com/en-us/library/dd233182.aspx
VD>http://langexplr.blogspot.com/2008/10/using-f-computation-expressions-to-read.html

Интересно, а можно ли ко всей этой кухне прикрутить сохранение (сериализацию) и возобновление состояния?
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: Ликбез по ComputationExpressions
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.10 20:25
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Интересно, а можно ли ко всей этой кухне прикрутить сохранение (сериализацию) и возобновление состояния?


Вряд ли. Там все завязано на монадах которые выполняют одну роль — связывают несколько вычислений происходящих в ленивой манере.

Это позволяет получить нечто похожее на континюэшон, но серализовать состояние не удастся, так как все основано на связанных ссылках на функции.

В прочем, я тут совершенный профан. Пусть лучше скажут те кто в этом что-то понимает.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Ликбез по ComputationExpressions
От: dsorokin Россия  
Дата: 23.04.10 04:15
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Интересно, а можно ли ко всей этой кухне прикрутить сохранение (сериализацию) и возобновление состояния?


Не совсем понятно, что ты имеешь ввиду. А вообще, продолжение является монадой. Поэтому если ты можешь решить свою задачу через продолжение, то есть шансы, что можно создать соответствующее вычислительное выражение. Кстати, async из F# построен на основе продолжения, и он умеет передавать свое состояние между потоками, так же как и распространять исключения между ними.
Re: Ликбез по ComputationExpressions
От: dsorokin Россия  
Дата: 23.04.10 04:18
Оценка:
Здравствуйте, hardcase, Вы писали:

H>какие задачи решает эта система макросов, для чего она нужна?


Я бы их использовал уже за то, что она умеет enumerable comprehension. Когда легко и непринужденно можно создавать объекты типа IEnumerable[_] в любом месте программы. Генераторы последовательности. В F# это зовется sequence comprehension. Ключевое слово seq. Здесь формат другой: comp enumerable {...}.
Re[2]: Ликбез по ComputationExpressions
От: Anton V. Kolotaev  
Дата: 23.04.10 09:54
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Вот, более полезный пример. Лениво возвращает список всех файлов, включая вложенные, из заданного каталога.


D>
    
D>    def filesUnderFolder (rootFolder : string) : IEnumerable [string]
D>    {
D>      comp enumerable
D>      {
D>        foreach (file in System.IO.Directory.GetFiles (rootFolder))
D>          yield file;
D>        foreach (dir in System.IO.Directory.GetDirectories (rootFolder))
D>          yieldcomp (filesUnderFolder (dir))
D>      }
D>    }
D>


Для сравнения оригинал на F#:
   let rec getAllFiles pattern folder  = 
      seq { for x in Directory.GetDirectories folder do yield! getAllFiles pattern x 
            for x in Directory.GetFiles(folder, pattern) do yield x }
Re[3]: Ликбез по ComputationExpressions
От: WolfHound  
Дата: 23.04.10 10:13
Оценка:
Здравствуйте, Anton V. Kolotaev, Вы писали:

AVK>Для сравнения оригинал на F#:

Для сравнения как следует отформатируем:
    def filesUnderFolder(pattern, rootFolder)
    {
      comp enumerable
      {
        foreach (file in Directory.GetFiles(rootFolder, pattern))
          yield file;
        foreach (dir in Directory.GetDirectories(rootFolder))
          yieldcomp filesUnderFolder(pattern, dir);
      }
    }

    let rec getAllFiles pattern folder  = 
        seq
        {
            for x in Directory.GetDirectories folder do
                yield! getAllFiles pattern x 
            for x in Directory.GetFiles(folder, pattern) do
                yield x 
        }

Итого: Разница в двух фигурных скобках и коротком алиасе который без труда можно добавить и в немерловый вариант.
  public macro @compEnumerable (expr)
  syntax ("comp", "enumerable", expr)
  {
    ComputationExpander.Expand (EnumerableBuilder.Instance, expr)
  }
  
  public macro @compEnumerableSeq (expr)
  syntax ("seq", expr)
  {
    ComputationExpander.Expand (EnumerableBuilder.Instance, expr)
  }
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Ликбез по ComputationExpressions
От: dsorokin Россия  
Дата: 23.04.10 10:31
Оценка:
Здравствуйте, WolfHound, Вы писали:

Спасибо за замечания. Учту. List comprehension оптимизирую через массив.

WH>Почему не:

WH>
WH>    public Delay[T] (cont : void -> IEnumerable[T]) : IEnumerable[T]
WH>    {
WH>      cont ();
WH>    }
WH>


Так делать нельзя. Теряется смысл в Delay. Потом, я написал отдельный DelayedEnumerable[T] : IEnumerable[T]. Через него будет эффективнее.

WH>Вот так гораздо лучше:

WH>
WH>  public module ForHelper
WH>  {
WH>    public Enumerate[T](cond : void -> bool, value : void -> T, change : void -> void) : IEnumerable[T]
WH>    {
WH>      while (cond())
WH>      {
WH>        yield value();
WH>        change();
WH>      }
WH>    }
WH>  }
WH>

WH>
WH>      def coll =
WH>        <[
WH>            EnumerableHelper.Delay (() =>
WH>              {
WH>                $init;
WH>                $postInit;
                
WH>                ForHelper.Enumerate(() => $cond, () => $var, () => $change)
WH>              })
WH>        ]>;
WH>


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

WH>Зачем нужно два void'а?

WH>
WH>  public sealed class ComputationVoid
WH>  {
WH>    public static Value : ComputationVoid = ComputationVoid ()
WH>  }

WH>  public variant FakeVoid
WH>  {
WH>    | FakeVoid
WH>  }
WH>


Это вопрос остается открытым. Собирался оставить один

WH>А еще я вернул ComputationExpressions.sln который ты зачемто удалил.

WH>Ибо многим работать в IDE банально удобнее.
WH>[/list]

Просто у меня нет полноценной студии. Есть VS C# Express 2005 и VS 2008 Shell. Не знаю, можно ли к ним прикрутить интеграцию?
Re[4]: Ликбез по ComputationExpressions
От: hardcase Пират http://nemerle.org
Дата: 23.04.10 10:55
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Просто у меня нет полноценной студии. Есть VS C# Express 2005 и VS 2008 Shell. Не знаю, можно ли к ним прикрутить интеграцию?


К Shell-у можно. Правда я всегда путаю Isolated и Integrated. Еще можно к SharpDevelop (формат проектов теперь идентичен).
/* иЗвиНите зА неРовнЫй поЧерК */
Re[5]: Ликбез по ComputationExpressions
От: dsorokin Россия  
Дата: 23.04.10 12:06
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Есть NemerleStudio. http://www.rsdn.ru/forum/prj.nemerle/2878763.1.aspx
Автор: Блудов Павел
Дата: 18.03.08

WH>Инсталятор немерла брать ессно свежий.
WH>Есдинственная проблема это то что NemerleStudio хочет расширение nsln вместо sln. Просто переименуй файл.

Спасибо. Похоже требуется VS 2008 Shell Isolated, а меня как раз стоит Integrated. Однако, F# там успешно работает. Придется снова качать.
Re[5]: Ликбез по ComputationExpressions
От: dsorokin Россия  
Дата: 23.04.10 12:08
Оценка:
Здравствуйте, hardcase, Вы писали:

H>К Shell-у можно. Правда я всегда путаю Isolated и Integrated. Еще можно к SharpDevelop (формат проектов теперь идентичен).


Пожалуй, SharpDevelop стоит снова мне поглядеть. Давно его не видел.
Re[4]: Ликбез по ComputationExpressions
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.04.10 14:19
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Не совсем понятно, что ты имеешь ввиду. А вообще, продолжение является монадой.


Нет не является. Продолжения вещь несомненно более мощьная. Их состояние можено сериализовать или клонировать.

Об это собственно и речь.

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

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

D>Поэтому если ты можешь решить свою задачу через продолжение, то есть шансы, что можно создать соответствующее вычислительное выражение. Кстати, async из F# построен на основе продолжения, и он умеет передавать свое состояние между потоками, так же как и распространять исключения между ними.


Как я понимаю там есть только CSP который, лично я, не понимаю как можно сериализовать или клонировать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Ликбез по ComputationExpressions
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.04.10 14:21
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>Я бы их использовал уже за то, что она умеет enumerable comprehension. Когда легко и непринужденно можно создавать объекты типа IEnumerable[_] в любом месте программы. Генераторы последовательности. В F# это зовется sequence comprehension. Ключевое слово seq. Здесь формат другой: comp enumerable {...}.


Это конечно полезно, для решения тех же задач есть и другие средства (макра лист компрешхншон, yield-методы, Linq, стандартные ФВП). Так что это скорее вопрос предпочтений и привычек.

Но, на мой взгляд, несомненно одно — чем больше возможностей тем лучше.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Ликбез по ComputationExpressions
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.04.10 14:26
Оценка:
Здравствуйте, dsorokin, Вы писали:

D>
    
D>    def filesUnderFolder (rootFolder : string) : IEnumerable [string]
D>    {
D>      comp enumerable
D>      {
D>        foreach (file in System.IO.Directory.GetFiles (rootFolder))
D>          yield file;
D>        foreach (dir in System.IO.Directory.GetDirectories (rootFolder))
D>          yieldcomp (filesUnderFolder (dir))
D>      }
D>    }
D>


Такой вопрос...

Народ пользуясь Немерлом частенько был разочарован тем, что yield нельзя применять внутри локальных функций.

Нельзя ли реализовать что-то вроде такого варианта:
    compdef filesUnderFolder (rootFolder : string) : IEnumerable [string]
    {
      foreach (file in System.IO.Directory.GetFiles (rootFolder))
        yield file;

      foreach (dir in System.IO.Directory.GetDirectories (rootFolder))
        yieldcomp (filesUnderFolder (dir))
    }

?

Вот это было бы просто супер удобно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Ликбез по ComputationExpressions
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.04.10 14:38
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Для сравнения как следует отформатируем:...


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

Лично для меня код отличается только при условии, что есть значительный синтаксический шум или если он отличается сематнически.

А эти два примера — это близницы браться с поправкой на синтаксис.

ЗЫ

Если уж кому-то охота заняться пенесометрией объемов кода, то наверно стоит применять identation-синтаксис.

Специально для таких любителей пенесометрии в снипетах немерла есть пример raytracer.
Вот список файлов из этого каталога.
[url=http://nemerle.googlecode.com/svn/nemerle/trunk/snippets/raytracer/ray-cs.cs]ray-cs.cs[/url]        4 249
[url=http://nemerle.googlecode.com/svn/nemerle/trunk/snippets/raytracer/ray2.ml]ray2.ml[/url]          2 793
[url=http://nemerle.googlecode.com/svn/nemerle/trunk/snippets/raytracer/ray3.ml]ray3.ml[/url]          3 030
[url=http://nemerle.googlecode.com/svn/nemerle/trunk/snippets/raytracer/ray.n]ray.n[/url]            2 962
[url=http://nemerle.googlecode.com/svn/nemerle/trunk/snippets/raytracer/ray2.n]ray2.n[/url]           3 024
[url=http://nemerle.googlecode.com/svn/nemerle/trunk/snippets/raytracer/ray3.n]ray3.n[/url]           3 470
[url=http://nemerle.googlecode.com/svn/nemerle/trunk/snippets/raytracer/ray-compressed.n]ray-compressed.n[/url] 2 725
[url=http://nemerle.googlecode.com/svn/nemerle/trunk/snippets/raytracer/ray-hand-opt.n]ray-hand-opt.n[/url]   3 574

Думаю их имена и размеры говорят сами за себя.

Языки группы ML конечно лидеры с точки зрения компактности записи кода, и Немерл от них не сильно отстает. А при должных стараниях может и перегнать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Ликбез по ComputationExpressions
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.04.10 14:41
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Для сравнения как следует отформатируем:

WH>
WH>    def filesUnderFolder(pattern, rootFolder)
WH>    {
WH>      comp enumerable
WH>      {
WH>        foreach (file in Directory.GetFiles(rootFolder, pattern))
WH>          yield file;
WH>        foreach (dir in Directory.GetDirectories(rootFolder))
WH>          yieldcomp filesUnderFolder(pattern, dir);
WH>      }
WH>    }
WH>


Кстати, в Немерле не указывать Directory (открыв модуль с помощью юсинга). Алгоритм вывода типов немерла это спокойно разрулит. А F# так может:
using System.IO.Directory;

def filesUnderFolder(pattern, rootFolder)
{
  comp enumerable
  {
    foreach (file in GetFiles(rootFolder, pattern))
      yield file;
    foreach (dir in GetDirectories(rootFolder))
      yieldcomp filesUnderFolder(pattern, dir);
  }
}

Мне кажется — нет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Ликбез по ComputationExpressions
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.04.10 14:49
Оценка:
Здравствуйте, WolfHound, Вы писали:

Согласен со всеми замечаниями кроме этого:

WH>

  • WH>Можно писать так:
    WH>
    WH>_testDo(10).Iter(WriteLine);
    WH>

    WH>местный вывод типов может даже в таких ситуациях разбираться...

    лучше пользоваться foreach-ем. Это делает код понятнее и лучше выглядит в отладчике (так как нет лишнего замыкания).
  • Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[5]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 23.04.10 15:05
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Нет не является. Продолжения вещь несомненно более мощьная. Их состояние можено сериализовать или клонировать.


    Вот, определение такой монады (пишу по памяти):

    type Cont a = (a -> Result) -> Result
    
    return a = \c -> c a
    
    bind m k = \c -> m (\a -> k a c)


    Более того, любую монаду можно свести к продолжению.

    VD>Представь себе, что некий ворфлоу заморозили в некоторой точке и это замороженное состояние превратили в поток байтов и записали в файл или поместили в поле БД.


    VD>Далее, через несколько дней, достали от туда, восстановили состояние в другой экземпляр и запустили с той же точки.


    Наверное, можно что-то сделать, хотя все равно большого смысла пока не вижу. Но если делать через монаду продолжения (Cont), то сериализовать поток управления, думаю, можно. Там исполнимый код как раз превращается в объекты памяти, которые уже поддаются сериализации средствами .NET (если функции сериализуются). Только какой ценой?

    А так можно дополнить монаду Cont функцией Save, которая будет принимать продолжение, сохранять его где-нибудь и затем завершать сеанс. Потом отдельно можно будет загрузить это продолжение и .. продолжить его выполнение. Computation expressions будут являться удобным eDSL для написания кода. Только я боюсь, что сериализовывать придется слишком много байт. Неэффективно будет.

    VD>Как я понимаю там есть только CSP который, лично я, не понимаю как можно сериализовать или клонировать.


    Не совсем понимаю.
    Re[3]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 23.04.10 15:11
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Нельзя ли реализовать что-то вроде такого варианта:

    VD>
    VD>    compdef filesUnderFolder (rootFolder : string) : IEnumerable [string]
    VD>    {
    VD>      foreach (file in System.IO.Directory.GetFiles (rootFolder))
    VD>        yield file;
    
    VD>      foreach (dir in System.IO.Directory.GetDirectories (rootFolder))
    VD>        yieldcomp (filesUnderFolder (dir))
    VD>    }
    VD>

    VD>?

    VD>Вот это было бы просто супер удобно.


    Я за такое не возьмусь. Это можно сделать параллельно. Мне кажется, что это не относится напрямую к самим computation expressions. Да и почему бы не написать лишнюю конструкцию comp enumerable {..}?

    Кстати, обновил svn. Enumerable comprehension стал на порядок эффективнее. Отдельное спасибо WolfHound за помощь в написание оптимизатора!
    Re[3]: Ликбез по ComputationExpressions
    От: WolfHound  
    Дата: 23.04.10 15:22
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Нельзя ли реализовать что-то вроде такого варианта:

    хъ
    VD>Вот это было бы просто супер удобно.
    Вот так вот оно работает:
      public macro DefCompEnum (name, args, expr)
      {
        def args = (args :> PExpr.Tuple).args.Map(PParameter);
        def name = (name :> PExpr.Ref).name;
        def res = ComputationExpander.Expand (EnumerableBuilder.Instance, expr);
        <[
          def $(name : name)(..$args)
          {
            $res;
          }
        ]>
      }
    
        DefCompEnum(filesUnderFolder, (rootFolder : string, pattern),
        {
          foreach (file in Directory.GetFiles(rootFolder, pattern))
            yield file;
          foreach (dir in Directory.GetDirectories(rootFolder))
            yieldcomp filesUnderFolder(dir, pattern);
        });
        filesUnderFolder("H:\\Video", "*").Iter(WriteLine);

    Но как его облачить в красивый синтаксис я пока не понял.
    ... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[6]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 23.04.10 15:42
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>Пожалуй, SharpDevelop стоит снова мне поглядеть. Давно его не видел.


    Погляди конечно, но пока что студия — это более надежный вариант.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[6]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 23.04.10 15:59
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>Вот, определение такой монады (пишу по памяти):


    D>
    D>type Cont a = (a -> Result) -> Result
    
    D>return a = \c -> c a
    
    D>bind m k = \c -> m (\a -> k a c)
    D>


    D>Более того, любую монаду можно свести к продолжению.


    Только к частному случаю.

    VD>>Представь себе, что некий ворфлоу заморозили в некоторой точке и это замороженное состояние превратили в поток байтов и записали в файл или поместили в поле БД.


    VD>>Далее, через несколько дней, достали от туда, восстановили состояние в другой экземпляр и запустили с той же точки.


    D>Наверное, можно что-то сделать


    Как? Добраться до состояния здесь практически не реально. А еще есть состояние окружающих объектов, которые получаются полностью изолированы.

    В общем, я не вижу как это сделать.

    D>, хотя все равно большого смысла пока не вижу.


    Это другой вопрос. К примеру, многие не видят смысла в монадах.
    Лично я смысл вижу. Сериализуемые континюэшоны — это натуральная бомба! С их помощью некоторые виды задач превращаются в элементарные, когда как без них решения получаются очень кривыми. Например, хранение сессии пользователя на сайте обеспечивающем сложную навигацию. Далее распараллеливание вычислений на разных машинах. Представь себя, просто сериализовал задачу и передал ее на другую машину. Там запустил и вычислил. Потом снова сериализовал и послал обратно. На этом деле даже STM реализуется в пол пинка.

    D> Но если делать через монаду продолжения (Cont), то сериализовать поток управления, думаю, можно.


    Ну, не знаю. Возможно я просто недооцениваю этот подход.
    А при этом мы сможем получить доступ к объектам обрабатываемым внутри этой монады? Ведь сериализовать нужно не только саму монаду, но и обрабатываемые в ней объекты.

    Вообще, если это реализовать — это было бы мега круто!

    D>Там исполнимый код как раз превращается в объекты памяти, которые уже поддаются сериализации средствами .NET (если функции сериализуются). Только какой ценой?


    Автоматическая сериализация в дотнете очень тормозная. Но ведь можно сделать и самопальную. Внутренние структуры ведь нам будут доступны?

    D>А так можно дополнить монаду Cont функцией Save, которая будет принимать продолжение, сохранять его где-нибудь и затем завершать сеанс. Потом отдельно можно будет загрузить это продолжение и .. продолжить его выполнение. Computation expressions будут являться удобным eDSL для написания кода. Только я боюсь, что сериализовывать придется слишком много байт. Неэффективно будет.


    Почему много? По идее это должно быть аналогично слепку стека на момент сериализации, плсю все объекты достижимые из него.

    Учитывая те возможности которые открываются при наличии такого решения я бы заплатил бы даже пятикратным оверхэдом!

    VD>>Как я понимаю там есть только CSP который, лично я, не понимаю как можно сериализовать или клонировать.


    D>Не совсем понимаю.


    Сори — CPS.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[4]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 23.04.10 16:06
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>Вот так вот оно работает:...

    WH>Но как его облачить в красивый синтаксис я пока не понял.

    Наверно как-то так:

      public macro DefCompEnum (name, args, expr)
      syntax ("compdef", fancName, args, expr)
      {
        def args = (args :> PExpr.Tuple).args.Map(PParameter);
        def name = (name :> PExpr.Ref).name;
        def res = ComputationExpander.Expand (EnumerableBuilder.Instance, expr);
        <[
          def $(name : name)(..$args)
          {
            $res;
          }
        ]>
      }

    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[5]: Ликбез по ComputationExpressions
    От: WolfHound  
    Дата: 23.04.10 16:14
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Наверно как-то так:

    хъ
    VD>
    А ты попробуй
    ... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[7]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 23.04.10 16:35
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Как? Добраться до состояния здесь практически не реально. А еще есть состояние окружающих объектов, которые получаются полностью изолированы.


    VD>В общем, я не вижу как это сделать.


    Там и код придется сериализовывать. Только он будет представлен в виде вычислений в монаде Cont. Фактически сначала по вычислительному выражению будет создано вычисление (некий объект), в котором будет закодирован весь процесс обработки. Затем это вычисление запускается и раскручивается. В любой момент можно прервать. Фактически нужно сериализовать функцию типа T -> void. Можно ограничится функцией FakeVoid -> void. Кстати, вот где нужна параметризация шаблона по void!

    VD>Это другой вопрос. К примеру, многие не видят смысла в монадах.

    VD>Лично я смысл вижу. Сериализуемые континюэшоны — это натуральная бомба! С их помощью некоторые виды задач превращаются в элементарные, когда как без них решения получаются очень кривыми. Например, хранение сессии пользователя на сайте обеспечивающем сложную навигацию. Далее распараллеливание вычислений на разных машинах. Представь себя, просто сериализовал задачу и передал ее на другую машину. Там запустил и вычислил. Потом снова сериализовал и послал обратно. На этом деле даже STM реализуется в пол пинка.

    Надо поразмыслить. Только повторюсь, медленно будет. И почему еще не сделали для F#?

    VD>Ну, не знаю. Возможно я просто недооцениваю этот подход.

    VD>А при этом мы сможем получить доступ к объектам обрабатываемым внутри этой монады? Ведь сериализовать нужно не только саму монаду, но и обрабатываемые в ней объекты.

    VD>Вообще, если это реализовать — это было бы мега круто!


    В своей библиотеке моделирования Aivika на F# я создал две монады Dynamics<'a> и DynamicsCont<'a>. Вторая есть частный случай монадного трансформера на базе Cont, параметризованного монадой Dynamics. В общем, монада Cont.

    Так вот, у меня там есть такие вещи как усыпление потока управления, блокировка в ожидании освобождения ресурса, возобновление через такой то промежуток времени и т.д. Сам код пишется как вычислительное выражение в монаде DynamicsCont<'a>. Выглядит как обычный код на F#. Только усыпление потока исполнения происходит в памяти. Сериализации нет. Но это все позволяет легко реализовать process-driven discrete event simulation (DES). Собственно, я пишу софт для моделирования, а эта библиотека — хобби.

    VD>Автоматическая сериализация в дотнете очень тормозная. Но ведь можно сделать и самопальную. Внутренние структуры ведь нам будут доступны?


    Будет функция типа FakeVoid -> void. Если сделаете параметризацию шаблона по void, то функция будет иметь тип void -> void. Вот, ее и надо сериализовать. А за этой простотой может скрываться очень много объектов!

    VD>Почему много? По идее это должно быть аналогично слепку стека на момент сериализации, плсю все объекты достижимые из него.


    VD>Учитывая те возможности которые открываются при наличии такого решения я бы заплатил бы даже пятикратным оверхэдом!


    Медленной будет не только сериализация, но и сам процесс исполнения кода. Фактически кода не будет. Будет запуск вычисления в монаде Cont. На самом деле, продолжения должны были бы поддерживаться на уровне CLR для эффективности. А так получится тормоз. Хотя в F# на это закрыли глаза и широко используют async.
    Re[2]: Ликбез по ComputationExpressions
    От: WolfHound  
    Дата: 23.04.10 16:51
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

      public macro @compList (expr)
      syntax ("comp", "list", expr)
      {
        ComputationExpander.Expand (ListBuilder (), expr)
      }
      
      public macro @compArray (expr)
      syntax ("comp", "array", expr)
      {
        ComputationExpander.Expand (ArrayBuilder (), expr)
      }
      
      public macro @compEnumerable (expr)
      syntax ("comp", "enumerable", expr)
      {
        ComputationExpander.Expand (EnumerableBuilder.Instance, expr)
      }

    Нашол серьезную проблему с данным синтаксисом.
    Ключевые слова list и array из первых двух макросов конфликтуют со стандартными ключивыми словами list и array.

    Пофиксил вот так:
      public macro @comp (builder, expr)
      syntax ("comp", builder, expr)
      {
        def builder = match (builder)
        {
          | PExpr.Ref(name) when name.Id == "list"       => Extensions.ListBuilder()
          | PExpr.Ref(name) when name.Id == "array"      => Extensions.ArrayBuilder()
          | PExpr.Ref(name) when name.Id == "enumerable" => Extensions.EnumerableBuilder.Instance
          | _                                            => DefaultBuilder(builder)
        }
        ComputationExpander.Expand (builder, expr)
      }

    В svn залил.
    ... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[6]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 23.04.10 17:09
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    VD>>Наверно как-то так:

    WH>хъ
    VD>>
    WH>А ты попробуй

    Я думал, что с мелочевкой ты справится. Вот рабочий вариант синтаксиса (начинку сам подставь):
      public macro DefCompEnum (prefix, body)
      syntax ("compdef", prefix, body)
      {
        match (prefix)
        {
          | <[ $name(..$args) ]> => <[ def $name = (..$args) => $body  ]>
          | _ => Message.FatalError(prefix.Location, "Expected fanc def: func_name(optional_parameters)")
        }
      }

    пример использования:
    compdef test(a, b)
    {
      a + b
    }
        
    WriteLine(test(2, 3));
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[8]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 23.04.10 17:24
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>Там и код придется сериализовывать. Только он будет представлен в виде вычислений в монаде Cont. Фактически сначала по вычислительному выражению будет создано вычисление (некий объект), в котором будет закодирован весь процесс обработки. Затем это вычисление запускается и раскручивается.


    А что будет с рекурсивными вызовами? Без рекурсии это будет ни чем не лучше итераторов (yield-методов).

    D>В любой момент можно прервать. Фактически нужно сериализовать функцию типа T -> void. Можно ограничится функцией FakeVoid -> void. Кстати, вот где нужна параметризация шаблона по void!


    Это не шаблоны — это типы (параметризованные типы или дженерики).

    Как сериализовать ссылку на функцию я себе даже представить не могу.

    D>Надо поразмыслить.


    +1

    D>Только повторюсь, медленно будет.


    Ну, это от реализации зависит. Я не представляю как это дело на монадах будет выглядеть, так что про скорость сказать не могу. Прямая реализация по моим расчетам должна была быть медленнее обычного кода, но не так уж чтобы значительно. Потом для воркфлоу скорость на так критична. Там не так моного логики. Скажем в некоторых явских фрэймворках для целей описания воркфлову используют скриптовый язык, с близким к яве синтаксисом, поддерживающий продолжения в своем рантайме. И по их словам им скорости хватало за глаза.

    D>И почему еще не сделали для F#?


    Хз. Возможно потому, что руки не дошли. Возможно просто в голову не пришло. А возможно есть какие-то сложности в реализации.

    Сам понимашь у них не так много народу который может это дело релизовать. Это ведь правка компилятора.

    Кстати, как тебе макросы? Теперь ты о них уже можешь кое-что сказать?
    Предрассудки по их поводу отпали?

    D>Так вот, у меня там есть такие вещи как усыпление потока управления, блокировка в ожидании освобождения ресурса, возобновление через такой то промежуток времени и т.д. Сам код пишется как вычислительное выражение в монаде DynamicsCont<'a>. Выглядит как обычный код на F#. Только усыпление потока исполнения происходит в памяти. Сериализации нет. Но это все позволяет легко реализовать process-driven discrete event simulation (DES). Собственно, я пишу софт для моделирования, а эта библиотека — хобби.


    Понятно, профессор. Но все же... Взлетит?

    D>Будет функция типа FakeVoid -> void. Если сделаете параметризацию шаблона по void, то функция будет иметь тип void -> void. Вот, ее и надо сериализовать. А за этой простотой может скрываться очень много объектов!


    Я решительно не понимаю как можно сериализовать ссылку на функцию.

    D>Медленной будет не только сериализация, но и сам процесс исполнения кода. Фактически кода не будет. Будет запуск вычисления в монаде Cont. На самом деле, продолжения должны были бы поддерживаться на уровне CLR для эффективности. А так получится тормоз. Хотя в F# на это закрыли глаза и широко используют async.


    Да. Наверно ты прав. Так что остается только попытаться создать ограниченные продолжения на базе переписывания кода класса (как я задумывал). Там оверхэд будет только при вызове методов (их параметры придется вместо стека располагать в динамических массивах). При этом сериализация превращается в линейный и прозрачный процесс.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[3]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 24.04.10 05:07
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>Пофиксил вот так:

    WH>
    WH>  public macro @comp (builder, expr)
    WH>  syntax ("comp", builder, expr)
    WH>  {
    WH>    def builder = match (builder)
    WH>    {
    WH>      | PExpr.Ref(name) when name.Id == "list"       => Extensions.ListBuilder()
    WH>      | PExpr.Ref(name) when name.Id == "array"      => Extensions.ArrayBuilder()
    WH>      | PExpr.Ref(name) when name.Id == "enumerable" => Extensions.EnumerableBuilder.Instance
    WH>      | _                                            => DefaultBuilder(builder)
    WH>    }
    WH>    ComputationExpander.Expand (builder, expr)
    WH>  }
    WH>

    WH>В svn залил.

    Здорово! Это как раз было слабым местом. Так можно добавлять разные нестандартные или конфликтующие с чем-то другим воркфлоу. Например, comp async {..} или comp option {..}.

    Среди важных задач остаются такие:

    1. Довершить foreach. Хитрый случай, когда тело foreach представляет из себя варианты паттерн-матчинга. Код локализован методом ComputationBuilder.ForEach.

    2. Приручить try-finally и try-catch. Думаю, будет несложно.

    3. Добавить using/usingcomp. Предвижу некоторую копипасту со стандартных макросов using из core.n
    Re[9]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 24.04.10 05:38
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>А что будет с рекурсивными вызовами? Без рекурсии это будет ни чем не лучше итераторов (yield-методов).


    В монаде Cont рекурсия часто используется. Например, монадический while определяется совершенно рекурсивно. Но там все дело в функциях. Рекурсия прячется в них и уже раскрывается во время их выполнения. Поэтому все нормально. Плюс работает оптимизация хвостовых вызовов.

    VD>Ну, это от реализации зависит. Я не представляю как это дело на монадах будет выглядеть, так что про скорость сказать не могу. Прямая реализация по моим расчетам должна была быть медленнее обычного кода, но не так уж чтобы значительно. Потом для воркфлоу скорость на так критична. Там не так моного логики. Скажем в некоторых явских фрэймворках для целей описания воркфлову используют скриптовый язык, с близким к яве синтаксисом, поддерживающий продолжения в своем рантайме. И по их словам им скорости хватало за глаза.


    И здесь могут быть интересны вычислительные выражения (воркфлоу). Они выглядят как обычный на Немерле код, который мы можем интерпретировать как угодно. Плюс работает проверка типов. Еще единообразие кода — низкая кривая обучения. В принципе можно тоже перегонять в скрипт, если написать свой ComputationBuilder. Затем исполнять этот скрипт внешне. Причем четко разделяется код на дополнительный и монадический.

    VD>Кстати, как тебе макросы? Теперь ты о них уже можешь кое-что сказать?

    VD>Предрассудки по их поводу отпали?

    Сложные чувства. С одной стороны расширяемый язык. С другой стороны сложнее создавать макросы, потому что эти макросы должны учитывать другие макросы...

    Что касается вычислительных выражений, то там все получается красиво и очень просто, но этому способствует гениальная задумка создателей самой идеи. Мы лишь адаптируем.

    VD>Да. Наверно ты прав. Так что остается только попытаться создать ограниченные продолжения на базе переписывания кода класса (как я задумывал). Там оверхэд будет только при вызове методов (их параметры придется вместо стека располагать в динамических массивах). При этом сериализация превращается в линейный и прозрачный процесс.


    Может быть, вычислительные выражения и пригодятся.
    Re[4]: Ликбез по ComputationExpressions
    От: WolfHound  
    Дата: 24.04.10 11:09
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    У меня тут крутится одна мысль:
    А что если разделить разбор выражений и собственно генерацию кода.
    Те мы сначала запихиваем все в вариант типа:
    variant CompExpr
    {
        | Sequence { seq : list[CompExpr] }
        | Return { expr : PExpr }
        | ReturnComp { expr : CompExpr }
    ...
    }


    Потом по этой структуре уже генерируем код.

    Это позволит:
    1)Упростить логику.
    2)Даст возможность более гибко генерировать код.
    3)Даст возможность оптимизировать выражения.
    ... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[6]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 24.04.10 11:12
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>Более того, любую монаду можно свести к продолжению.


    Вот именно, но не наоборот.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[10]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 24.04.10 11:47
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    VD>>А что будет с рекурсивными вызовами? Без рекурсии это будет ни чем не лучше итераторов (yield-методов).


    D>В монаде Cont рекурсия часто используется. Например, монадический while определяется совершенно рекурсивно. Но там все дело в функциях. Рекурсия прячется в них и уже раскрывается во время их выполнения. Поэтому все нормально. Плюс работает оптимизация хвостовых вызовов.


    Я говорю о том как будет сериализоваться информация о глубине рекурсии и значених параметров?

    D>И здесь могут быть интересны вычислительные выражения (воркфлоу). Они выглядят как обычный на Немерле код, который мы можем интерпретировать как угодно. Плюс работает проверка типов. Еще единообразие кода — низкая кривая обучения. В принципе можно тоже перегонять в скрипт, если написать свой ComputationBuilder. Затем исполнять этот скрипт внешне. Причем четко разделяется код на дополнительный и монадический.


    Скрипт то как раз не нужен. Нужны именно продолжения. Возможно ограниченные (например, ОО-классом), но с поддержкой рекурсии и вызовов функций.

    Пока что я что-то сомневаюсь, что на монадах может получиться что-то стоящее.

    D>Сложные чувства. С одной стороны расширяемый язык. С другой стороны сложнее создавать макросы, потому что эти макросы должны учитывать другие макросы...


    Ну, дык метапрограммировние по любому сложнее просто программирования.
    Что касается учета других макросов, то это как раз требуется довольно редко. Обычно они получаются довольно назависимыми.
    А вообще, просто нужен опыт. Ты ведь с ними возишся около недели. Правильно?

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


    Ну, так уж и гениальная . Просто хорошо продуманное решение. Я бы сказал — нормальная инженерная работа. К тому же база была хорошо проработана в хаскеле. Да что уж там? Можно даже сказать в теории категорий (если не ошибаюсь).

    VD>>Да. Наверно ты прав. Так что остается только попытаться создать ограниченные продолжения на базе переписывания кода класса (как я задумывал). Там оверхэд будет только при вызове методов (их параметры придется вместо стека располагать в динамических массивах). При этом сериализация превращается в линейный и прозрачный процесс.


    D>Может быть, вычислительные выражения и пригодятся.


    В принципе можно даже попытаться сделать несколько реализаций. Где только на это взять времени и сил. Хотя это точно будет киллер-фичей... только как всегда для узкого круга посвященных .
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[5]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 24.04.10 12:57
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

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


    WH>У меня тут крутится одна мысль:

    WH>А что если разделить разбор выражений и собственно генерацию кода.
    WH>Те мы сначала запихиваем все в вариант типа:
    WH>
    WH>variant CompExpr
    WH>{
    WH>    | Sequence { seq : list[CompExpr] }
    WH>    | Return { expr : PExpr }
    WH>    | ReturnComp { expr : CompExpr }
    WH>...
    WH>}
    WH>


    WH>Потом по этой структуре уже генерируем код.


    WH>Это позволит:

    WH>1)Упростить логику.
    WH>2)Даст возможность более гибко генерировать код.
    WH>3)Даст возможность оптимизировать выражения.

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

    Сейчас предлагаю завершить текущую схему. Я добавил более полную реализацию foreach (с матчингом и приведением :>) и блок try-finally. Из основных остались try-catch и using/usingcomp.
    Re[7]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 24.04.10 13:06
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    D>>Более того, любую монаду можно свести к продолжению.


    VD>Вот именно, но не наоборот.


    Зато можно построить монаду Cont. Этого достаточно для многих практических задач. Тогда с помощью вычислительных выражений становится очень легко и просто создавать эти самые продолжения. Async из F# в своей основе есть продолжение, но которое еще умеет распространять исключения между потоками исполнения.
    Re[11]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 24.04.10 13:18
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Я говорю о том как будет сериализоваться информация о глубине рекурсии и значених параметров?


    Наверное как граф объектов. Но для этого надо уметь сериализовывать функции и замыкания.

    VD>Ну, дык метапрограммировние по любому сложнее просто программирования.

    VD>Что касается учета других макросов, то это как раз требуется довольно редко. Обычно они получаются довольно назависимыми.
    VD>А вообще, просто нужен опыт. Ты ведь с ними возишся около недели. Правильно?

    Меньше Но время от времени еще увлекаюсь Common Lisp. Так что, к макросам привыкший.

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


    VD>Ну, так уж и гениальная . Просто хорошо продуманное решение. Я бы сказал — нормальная инженерная работа. К тому же база была хорошо проработана в хаскеле. Да что уж там? Можно даже сказать в теории категорий (если не ошибаюсь).


    Нет, здесь свое. На мой взгляд основная фишка в том, что код, написанный в вычислительных выражениях, почти ничем не отличается от обычного кода на F# или Немерле. Это просто гениальная вещь! В одном ряду с linq, где по забавному совпадению тоже монады
    Re[8]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 24.04.10 13:55
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>Зато можно построить монаду Cont. Этого достаточно для многих практических задач. Тогда с помощью вычислительных выражений становится очень легко и просто создавать эти самые продолжения. Async из F# в своей основе есть продолжение, но которое еще умеет распространять исключения между потоками исполнения.


    Как я понимаю, монады по своей сути — это CPS-продолжения. В бинд ведь как раз и передается функция которую нужно вызвать вслед за вычислением. Вот только это никак не способствует серилизации состояния вычисления.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[12]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 24.04.10 14:07
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

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


    VD>>Я говорю о том как будет сериализоваться информация о глубине рекурсии и значених параметров?


    D>Наверное как граф объектов. Но для этого надо уметь сериализовывать функции и замыкания.


    А как это вообще можно сделать? Да и вообще, что под этим понимаетя?

    D>Меньше Но время от времени еще увлекаюсь Common Lisp. Так что, к макросам привыкший.


    А, да! Лисповская практика очень полезна. За исключением манипуляций с типами выражений идеология очень похожа.
    В прочем она похоже полезна всегда .

    D>Нет, здесь свое. На мой взгляд основная фишка в том, что код, написанный в вычислительных выражениях, почти ничем не отличается от обычного кода на F# или Немерле.


    Мне кажется в хаскеле это не так потому, что его авторы были очень большими пуристами и "нормальное программирование" у них все ушло в монады.

    D>Это просто гениальная вещь! В одном ряду с linq, где по забавному совпадению тоже монады


    Я в linq монады ну ни как не могу узреть. С натяжкой SelectMeny, но ведь он а) редко используется, и б) имеет (по крайней мере для меня) не монадический смысл.

    Я скорее рассматриваю linq как качественно портированый предюд из Хаскеля.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[13]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 24.04.10 14:23
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    D>>Наверное как граф объектов. Но для этого надо уметь сериализовывать функции и замыкания.


    VD>А как это вообще можно сделать? Да и вообще, что под этим понимаетя?


    Я понимаю так, что функции и замыкания представлены как ООП-объекты в IL. Вот их и надо бы сериализовать вместе со всеми связями и состояниями. Только реально ли? Думаю, тупиковая идея.

    VD>Я в linq монады ну ни как не могу узреть. С натяжкой SelectMeny, но ведь он а) редко используется, и б) имеет (по крайней мере для меня) не монадический смысл.


    VD>Я скорее рассматриваю linq как качественно портированый предюд из Хаскеля.


    С linq не работал и почти ничего не знаю о нем, не читал. Но мне кажется, что под from может скрываться defcomp (bind), под select — return, а под selectMany — returncomp. Where — альтернатива if при условии существования zero (пустая коллекция). Если бы были if и zero, то тогда можно было where определить через все другое:

    def where (coll, pred)
    {
      comp builder
      {
        defcomp x = coll;
        if pred (x) 
          return x
        else
          returncomp zero
      }
    }
    Re[13]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 24.04.10 15:59
    Оценка:
    У меня есть вопрос ко всем. Правильно ли я понимаю следующую вещь? Есть тип TryCase, который задает один обработчик из блока try-catch. Вот его конструкторы:

    match (c : TryCase)
    {
      | Catch (exn, exn_ty, handler) => ...
      | Filter (exn, exn_ty, filter, handler) => ...
      | Ellipsis (handler) => ...
    }


    Меня интересуют переменные handler. Действительно ли это та часть конструкций, которая следует после символа => в части catch? Особенно смущает filter. Что он значит?

    Если я правильно понимаю, что за => отвечают только переменные handler, то могу сказать, что реализован try-catch для вычислительных выражений. Я там сделал немного не так как в F#. Пошел на хитрость. Исключение перевозбуждается. Так стало намного проще. В F# же заменяют блок catch на паттерн матчинг, что напряжно делать, да и смысла большого не вижу.

    Итог такой. Уже есть try-finally и try-catch (если я прав на счет handler). Для полноценной поддержки осталось добавить using/usingcomp.
    Re[14]: Ликбез по ComputationExpressions
    От: hardcase Пират http://nemerle.org
    Дата: 24.04.10 16:12
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>У меня есть вопрос ко всем. Правильно ли я понимаю следующую вещь? Есть тип TryCase, который задает один обработчик из блока try-catch. Вот его конструкторы:


    D>
    D>match (c : TryCase)
    D>{
    D>  | Catch (exn, exn_ty, handler) => ...
    D>  | Filter (exn, exn_ty, filter, handler) => ...
    D>  | Ellipsis (handler) => ...
    D>}
    D>


    D>Меня интересуют переменные handler. Действительно ли это та часть конструкций, которая следует после символа => в части catch? Особенно смущает filter. Что он значит?


    Если не ошибаюсь то вот интерпретация:


    Catch:

    try {
    } catch {
       | e is ArgumentNullException => 
    }



    Filter:

    try {
    } catch {
       | e is ArgumentNullException when e.Message.Contains("x") => 
    }


    Ellipsis:

    try {
    } catch {
       | _ => 
    }
    /* иЗвиНите зА неРовнЫй поЧерК */
    Re[15]: Ликбез по ComputationExpressions
    От: hardcase Пират http://nemerle.org
    Дата: 24.04.10 16:14
    Оценка:
    Здравствуйте, hardcase, Вы писали:

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



    D>>Меня интересуют переменные handler. Действительно ли это та часть конструкций, которая следует после символа => в части catch? Особенно смущает filter. Что он значит?


    А хендлер, да это то, что следует после =>.
    /* иЗвиНите зА неРовнЫй поЧерК */
    Re[16]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 24.04.10 16:24
    Оценка:
    Здравствуйте, hardcase, Вы писали:

    H>А хендлер, да это то, что следует после =>.


    Спасибо! Тогда тестируйте! По-моему enumerable comprehension получается довольно аппетитным
    Re[14]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 24.04.10 20:21
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>Я понимаю так, что функции и замыкания представлены как ООП-объекты в IL. Вот их и надо бы сериализовать вместе со всеми связями и состояниями. Только реально ли? Думаю, тупиковая идея.


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

    D>С linq не работал и почти ничего не знаю о нем, не читал. Но мне кажется, что под from может скрываться defcomp (bind), под select — return, а под selectMany — returncomp. Where — альтернатива if при условии существования zero (пустая коллекция).


    Ага. Астрономы тоже в звездах видят тельцов и дев .
    Реальности жизни несколько банальнее. select — это map, where — filter и т.д.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[14]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 24.04.10 20:39
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>Меня интересуют переменные handler. Действительно ли это та часть конструкций, которая следует после символа => в части catch?


    Да.
    В немерле обработчики искючений аналогичны вхождениям оператора match (описывающиеся конструкцией MatchCase).

    D>Особенно смущает filter. Что он значит?


    Скажем если мы имеем следующий код:
    try
    {
      ...
    }
    catch
    {
      | e is SomeException when e.SomeProperty == 123
    }

    то такое вхождение catch-а записывается как TryCase.Filter.
    Собственно это легко понять если сделать поиск по TryCase.Filter в файле ncc\parsing\MainParser.n.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[15]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 24.04.10 21:34
    Оценка:
    Здравствуйте, hardcase, Вы писали:

    H>Ellipsis:


    H>
    H>try {
    H>} catch {
    H>   | _ => 
    H>}
    H>


    Здесь ошибаешься. Ellipsis — это $-выражение в квази-цитате.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[15]: Ликбез по ComputationExpressions
    От: Аноним  
    Дата: 24.04.10 21:35
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Ага. Астрономы тоже в звездах видят тельцов и дев .


    Астрономы или астрологи?

    VD>Реальности жизни несколько банальнее. select — это map, where — filter и т.д.


    IEnumerable + Linq, в особенности с методом SelectMany являются реализацией монады списка. Докладнее можно почитать, например тут: http://codebetter.com/blogs/matthew.podwysocki/archive/2008/10/13/functional-c-linq-as-a-monad.aspx

    Или посмотреть тут: http://www.infoq.com/interviews/LINQ-Erik-Meijer
    Re[16]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 24.04.10 21:47
    Оценка:
    Здравствуйте, Аноним, Вы писали:

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


    VD>>Ага. Астрономы тоже в звездах видят тельцов и дев .


    А>Астрономы или астрологи?


    Астрономы. Астрологи идут дальше и видят связь между тем чего нет и тем чего не может быть.

    А>IEnumerable + Linq, в особенности с методом SelectMany являются реализацией монады списка.


    А если скажем без IEnumerable? Или без SelectMany?

    А>Докладнее можно почитать, например тут: http://codebetter.com/blogs/matthew.podwysocki/archive/2008/10/13/functional-c-linq-as-a-monad.aspx


    А>Или посмотреть тут: http://www.infoq.com/interviews/LINQ-Erik-Meijer


    Ну, да. Ну, да. Это все я видел. Я же говорю... В прочем не буду повторяться (см. выше).
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[16]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 25.04.10 04:22
    Оценка:
    Здравствуйте, VladD2, Вы писали:

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


    H>>Ellipsis:


    H>>
    H>>try {
    H>>} catch {
    H>>   | _ => 
    H>>}
    H>>


    VD>Здесь ошибаешься. Ellipsis — это $-выражение в квази-цитате.


    А можно подробнее? Ellipsis имеет один параметр body. Сейчас этот body у меня преобразовывается в поисках монады. Мне интересно знать, насколько это корректно. Можно этот Ellipsis создать в коде?
    Re[15]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 25.04.10 05:52
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Реальности жизни несколько банальнее. select — это map и т.д.


    Ну, да. Функция fmap для монады:

    def fmap (coll, f)
    {
      comp builder
      {
        defcomp x = coll;
        return (f (x))
      }
    }


    Вот тут, кстати, было бы хорошо отойти от канонов F# и генерировать общий код для fmap как в хаскеле. Над этим надо будет озадачиться.
    Re: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 25.04.10 06:26
    Оценка:
    Тут ко мне пришла гениальная идея! (как-то запоздало...) Можно не изобретать свой аналог async аля F#. Можно его просто использовать в Немерле, но со своим синтаксисом вычислительных выражений! Со своими foreach, паттерн-матчингом, repeat и do-while. Для этого нужны две вещи:

    1) либо написать прослойку, которая давала бы немерлевский билдер (методы практически также называются), либо генерировать нужный код напрямую через ComputationBuilder (предпочтительнее);

    2) установленный run-time для F# (идет вместе с .NET v4).

    Тогда можно будет писать на Немерле в стиле:

    def get_html_async (url : string)
    {
      comp async 
      {
        def request = WebRequest.Create(url);
        defcomp response = request.AsyncGetResponse();
        def stream = response.GetResponseStream();
        def reader = StreamReader(stream);
        defcomp text = reader.AsyncReadToEnd();  
        return text  
      }  
    }


    В общем, считайте, что async из F# уже почти есть в Немерле

    Знаю, что в Немерле уже есть свой async, но он какой-то другой.
    Re[16]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 25.04.10 13:42
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    VD>>Реальности жизни несколько банальнее. select — это map и т.д.


    D>Ну, да. Функция fmap для монады:


    D>
    D>def fmap (coll, f)
    D>{
    D>  comp builder
    D>  {
    D>    defcomp x = coll;
    D>    return (f (x))
    D>  }
    D>}
    D>


    Какие монды? Вот определение Select-а:
    public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)

    Чем это отличается от MapLazy из стандартной библиотеки немерла:
    public MapLazy[From, To](this source : SCG.IEnumerable[From], convert : From -> To) : SCG.IEnumerable[To]

    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[17]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 25.04.10 14:10
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Какие монды? Вот определение Select-а:


    В основе лежит монада списка (сюрприз!). Но как я понял, можно определять в linq и свои монады. Только непонятно, насколько эквивалентно получается тем же вычислительным выражениям.
    Re[18]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 25.04.10 14:30
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Куда же подробнее? Это заглушка для квази-цитирования. Может появляться только внутри цитат. Нужно для генерации кода вхождения путем подстановки спласа.


    VD>Самому еще не разу не приходилось генерировать обработчики catch-ей, но это должно выгдядеть как-то так:

    VD>
    VD><[
    VD>try
    VD>{
    VD>}
    VD>catch 
    VD>{
    VD>  ..$(GenerateExcetpionHandlers())
    VD>}
    VD>]>
    VD>


    Я не понял, что с этим делать. Поэтому добавил вывод ошибки компиляции для этого TryCase.Ellipsis. Мне нужно больше информации, чтобы понять.

    Сегодня добавил using. Он такой же. Только в нем нельзя использовать mutable. Зато можно использовать defcomp:

      comp builder
      {
        using (defcomp x = resource_in_monad)
        {
          ...
        }
      }


    В общем, я сделал все, что хотел. Можно назвать готовой бетой. Теперь исправления ошибок, если таковые будут. Остается только неясность с FakeVoid (в F# для инстанцирования генериков по как бы void используется класс Unit, поддерживаемый на уровне компилятора). Плюс нужно написать документацию. Но теперь темп будет уже не таким.
    Re[18]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 25.04.10 15:22
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>В основе лежит монада списка (сюрприз!).


    В основе чего? Какую роль она выполняет в языке неленивым исполнением?

    D>Но как я понял, можно определять в linq и свои монады. Только непонятно, насколько эквивалентно получается тем же вычислительным выражениям.


    Я одного не понимаю... неужели нельзя верить свои глазам?

    Я понимаю зачем нужны монады в ComputationExpressions. Более того монады тут видны не вооруженным взглядом. Есть те самые бинд, ретон и т.п.

    А зачем нужны монады в банальной библиотеке ФВП? И где те самые бинд, ретон и т.п.?
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[19]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 25.04.10 15:40
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>В основе чего? Какую роль она выполняет в языке неленивым исполнением?


    Неленивость (энергичность) тут ни причем.

    VD>Я одного не понимаю... неужели нельзя верить свои глазам?


    VD>Я понимаю зачем нужны монады в ComputationExpressions. Более того монады тут видны не вооруженным взглядом. Есть те самые бинд, ретон и т.п.


    VD>А зачем нужны монады в банальной библиотеке ФВП? И где те самые бинд, ретон и т.п.?


    Ну, выше же была ссылка. Там определялась монада Maybe через linq. Где-то я видел определение на linq чего то типа парсека. Да, и вообще, устал я уже от этой темы. Ты лучше enumerable comprehension зацени вместе со всеми плюшками

    Например, в обычной ситуации у меня компилятор обламывался на yield, использованном внутри try-catch-finally. В enumerable comprehension это все должно работать! Using должен работать, даже с секцией catch! Foreach практически такой же как и стандартный. Загляденье.
    Re[19]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 25.04.10 15:57
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>Я не понял, что с этим делать.


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

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


    Будут, не сомневайся . Если программа запустилась с первого раза, ищите ошибку в компиляторе (с)

    D>Остается только неясность с FakeVoid (в F# для инстанцирования генериков по как бы void используется класс Unit, поддерживаемый на уровне компилятора).


    Можно внести в стандартную библиотеку:
    public struct unit { }

    может быть еще попытаться добавить неявные приведения типов от void к unit и обратно.

    D>Плюс нужно написать документацию. Но теперь темп будет уже не таким.


    Вот как документацию писать, так...
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[20]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 25.04.10 16:25
    Оценка:
    Здравствуйте, dsorokin, Вы писали:

    D>Неленивость (энергичность) тут ни причем.


    А что здесь причем?

    D>Ну, выше же была ссылка. Там определялась монада Maybe через linq. Где-то я видел определение на linq чего то типа парсека.


    У тебя нарушена причино-следственная связь.

    Конечно, используя linq без проблем можно описать что-то типа монады, так как SelectMeny имеет ту же сигнатуру, что и бинд. Но вот обратное не верно! Линк это библиотека ФВП. Мало чем отличающаяся от прелюда хаскеля. И это вся правда!

    D>Да, и вообще, устал я уже от этой темы. Ты лучше enumerable comprehension зацени вместе со всеми плюшками


    Заценю конечно. Просто я привык на практике заценивать, а задачи пока под это дело особо нет.
    У меня сейчас вообще задачи — баги в компиляторе и интеграции править. Вот за вчера два поправил.

    D>Например, в обычной ситуации у меня компилятор обламывался на yield, использованном внутри try-catch-finally. В enumerable comprehension это все должно работать! Using должен работать, даже с секцией catch! Foreach практически такой же как и стандартный. Загляденье.


    Да, не плохо! Но и у ComputationExpressions тоже своих ограничений хватает. Главное из которых — это замкнутый подъязык. Те же макросы в нем не будут работать.

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

    D>2) установленный run-time для F# (идет вместе с .NET v4).


    4.0 вряд ли запустится под 3.5. Кроме того не ясно что с лицензией.

    По идее раньше F# был в двух версиях, в том числе и в версии для 3.5. Не знаю выходила ли версия для 3.5 после выхода четвертого фрэймворка. Если выходила, то можно ею воспользоваться.

    А что там в этой поддержке async-а такого есть?
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[17]: Ликбез по ComputationExpressions
    От: Аноним  
    Дата: 25.04.10 20:37
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>А если скажем без IEnumerable? Или без SelectMany?


    Без IEnumerable будет другая монада Без SelectMany будет моноид какой-нибудь или функтор. Наверное. Я не спец в теории категорий

    VD>Ну, да. Ну, да. Это все я видел. Я же говорю... В прочем не буду повторяться (см. выше).


    Я только хотел сказать, что и в программировании один и тот же феномен можно описывать разными способами. linq можно рассматривать как набор extension-методов, как mixin к коллекциям, как введение синтаксиса SQL в си-шарп и vb, как библиотеку комбинаторов, как порт хаскеллового прелюда, как обобщенный механизм запросов к источникам данных или вот как специальную нотацию для монад.

    Никто, конечно же, не заставляет считать linq монадой, но это утверждение намного обоснованней, чем названия созвездий (имхо).

    Монады, они ведь везде. Даже nullable можно считать монадой, если очень захотеть.
    Re[3]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 26.04.10 02:01
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>4)Агенты слишком куцое решение.

    WH>По хорошему нужно сделать каналы.
    WH>А на каналах агенты делаются одной левой.
    WH>Причем можно сделать весьма навороченные как в сингулярити.

    Всегда надо знать кода нужно остановиться. А то нафантазировать можно столько, что за всю жизнь не разгребешь.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[3]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 26.04.10 06:52
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>Тогда можно будет делать так:

    WH>
    WH>    def poolContext = ThreadPoolExecutionContext(10);
    WH>    def guiContext = WindowsFormsExecutionContext(form);
        
    WH>    def worker()
    WH>    {
    WH>        comp async
    WH>        {
    WH>            callcomp Async.SwitchTo(poolContext);
    WH>            //делаем что-то тяжолое в контексте пула.
    WH>            callcomp Async.SwitchTo(guiContext);
    WH>            //а тут спокойно ковыряемся в gui.
    WH>            returncomp worker();
    WH>        }
    WH>    }
    WH>    poolContext.Start(worker());
    WH>


    Я добавил в сниппеты FSharpAsync. Там билдер fsasync для Nemerle, написанный на F#. Это обертка вокруг тамошнего async workflow. Накладной расход в том, что постоянно вызывается метод Delay самого первоначального async. Чтобы полноценно использовать fsasync, нужны асинхронные extensions для типов вроде FileStream.
    Re[20]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 26.04.10 07:07
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Это возможность другим макросам сгенерировать код обработчиков исключений. В общем случае нужно просто давать сгенерировать код и потом обрабатывать сгенерированный код.


    Увы, это входит в противоречие с идеологией однопроходного и достаточно примитивного макроса comp. Хотя есть одно решение. Можно волюнтаристски трактовать такие обработчики try как монадические. Тогда можно сделать через отложенный макрос. Оборотная сторона в том, что может потребоваться метод Zero у билдера там, где можно было бы обойтись и без него.

    D>>Остается только неясность с FakeVoid (в F# для инстанцирования генериков по как бы void используется класс Unit, поддерживаемый на уровне компилятора).


    VD>Можно внести в стандартную библиотеку:

    VD>
    VD>public struct unit { }
    VD>

    VD>может быть еще попытаться добавить неявные приведения типов от void к unit и обратно.

    Вообще-то, такие приведения должен отрабатывать сам компилятор. Пока неясно, можно ли ограничиться одной перегрузкой. Но получается не так красиво, потому что при создании билдера нужно учитывать тип FakeVoid. И сейчас нельзя писать return (), нужно — return FakeVoid.Value. Но по идее в обычном коде такие выражения не должны встречаться.
    Re[21]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 26.04.10 07:21
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Да, не плохо! Но и у ComputationExpressions тоже своих ограничений хватает. Главное из которых — это замкнутый подъязык. Те же макросы в нем не будут работать.


    Если внутри макросов не используются defcomp, return, returncomp, call и callcomp, то легко! Макросы будут оставлены как есть.
    Re[9]: Ликбез по ComputationExpressions
    От: lomeo Россия http://lomeo.livejournal.com/
    Дата: 26.04.10 18:33
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Как я понимаю, монады по своей сути — это CPS-продолжения.


    Я заранее извиняюсь за оффтоп, но это действительно удивительный факт — такая простая вещь оказывается настолько непонятой. Да, я опять о монадах.

    Вопрос, ты знаешь, что такое моноид (ассоциативная операция)? На всякий случай напомню. Это операция, для которой верно следующее
    (a + b) + c = a + (b + c)


    Что такое функтор тебе известно. Я о преобразовании Fun<A,B> в Fun<T<A>, T<B>>, сохраняющем структуру. Пример — дерево в точно такое же дерево, но значения каким-то образом преобразованы (возведены в квадрат, сериализованы в строку, выплачена премия).

    Так вот, монада — это моноид над функторами. Всё. Моноид над функторами.

    Есть ассоциативная операция над списками (конкатенация), значит список — монада. Есть ассоциативная операция над императивом (точка с запятой из сишных языков) — значит императив — монада. Есть ассоциативная операция над продолжением (последующий вызов), значит продолжения — монада. Т.к. функторов везде полно (большинство типов T<A> являются функторами — как контейнеры, так и оболочки над функциями) и т.к. ассоциативных операций ещё больше, то неудивительно, что мы постоянно натыкаемся на монады.

    Вопрос, в тех реализациях интерфейса linq, с которыми ты знаком результат
    x.SelectMany(y => f(y).SelectMany(g)

    эквивалентен
    x.SelectMany(f).SelectMany(g)

    ?

    Если да, то это тоже монада. Можно её видеть, можно не видеть, от этого она монадой быть не перестанет.

    Попытка удалась?
    Re[10]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 26.04.10 19:51
    Оценка:
    Здравствуйте, lomeo, Вы писали:

    L>Я заранее извиняюсь за оффтоп, но это действительно удивительный факт — такая простая вещь оказывается настолько непонятой. Да, я опять о монадах.


    Какие люди в нашей деревне!
    Привет!

    L>...Так вот, монада — это моноид над функторами. Всё. Моноид над функторами.


    Проблема в том, что в языках которые мы тут обсуждаем (Немерле и возможно Шарп) просто нет понятий "функтор". Так что их пользователям твои рассказы просто разрывают мозг. Пусть те кто считает себя C#-программистом и кому эти рассказы не рвут мозг кинет в меня камень (путем установки минуса, плиз, а не явно).

    L>Есть ассоциативная операция над списками (конкатенация), значит список — монада.


    Значит если мы не добавим с наш список SelectMany, то мы имеем дел с простым списком?

    L>Есть ассоциативная операция над императивом (точка с запятой из сишных языков) — значит императив — монада.


    А если язык не ленивый по умолчанию, и точка запятой и так позволяет выполнить два выражения последовательно?

    L> Есть ассоциативная операция над продолжением (последующий вызов), значит продолжения — монада.


    А можно так: Есть передача в качестве параметра функции которая продолжит вычисление, значит монада — это продолжение?

    Или тут важна ассоциативность?

    L>Т.к. функторов везде полно (большинство типов T<A> являются функторами — как контейнеры, так и оболочки над функциями) и т.к. ассоциативных операций ещё больше, то неудивительно, что мы постоянно натыкаемся на монады.


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

    Мне кажется, что монады есть только там где а) есть факт связи двух вычислений по средствам функций, б) человек использующий это дело понимает что пользуется именно этим инструментом, а не отталкивается от какой-то другой теории (например, что он тупо выпрямляет дерево или вложенные списки в плоский список). Согласен?

    L>Вопрос, в тех реализациях интерфейса linq, с которыми ты знаком результат

    L>
    L>x.SelectMany(y => f(y).SelectMany(g)
    L>

    L>эквивалентен
    L>
    L>x.SelectMany(f).SelectMany(g)
    L>

    L>?

    L>Если да, то это тоже монада. Можно её видеть, можно не видеть, от этого она монадой быть не перестанет.


    L>Попытка удалась?


    Ну, как сказать. Разглядеть монаду (при желании) в SelectMany я мог и раньше. Точнее разглядеть я мог сигнатуру бинда. Но вот убей меня я не могу понять зачем приплетать монады туда где от их (логического) использования нет никакого смысла.

    В прочем, с философской точки зрения попытка хорошая. Просто мы совершенно разные люди. Тебе видимо чужд не научный метод определения пола кошаков (бросил... побежала — кошка, побежал — кот) .

    ЗЫ

    Кстати, ты как специаилст в области монад и другой нечисти, не мог бы нам объяснить, что "мощнее" полноценное (не ограниченное) продолжение или монада.

    Ну, в смысле отвата на два вопроса:
    1. Можно ли выразить любую монаду продолжением?
    2. Можно ли выразить любое продолжение монадой?
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[10]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 26.04.10 19:53
    Оценка:
    Здравствуйте, lomeo, Вы писали:

    Да... и за одно ответь, плиз, на вопрос. Что проще (и вообще реалистично ли это?) сделать сериализуемое ComputationExpressions или реализовать продолжение (ограниченное рамками одного класса) путем переписывания кода таким образом, чтобы он складывал параметры вызовов в списки, а не в стек?
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[11]: Ликбез по ComputationExpressions
    От: lomeo Россия http://lomeo.livejournal.com/
    Дата: 28.04.10 15:15
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD>Да... и за одно ответь, плиз, на вопрос. Что проще (и вообще реалистично ли это?) сделать сериализуемое ComputationExpressions или реализовать продолжение (ограниченное рамками одного класса) путем переписывания кода таким образом, чтобы он складывал параметры вызовов в списки, а не в стек?


    Ой, я не специалист. Сначала почитаю про то, что такое ComputationExpressions.
    Re[12]: Ликбез по ComputationExpressions
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 28.04.10 19:12
    Оценка:
    Здравствуйте, lomeo, Вы писали:

    L>Ой, я не специалист. Сначала почитаю про то, что такое ComputationExpressions.


    Монады переименованные для того чтобы не пугать гражданских и которым придан эдакий красивый синтаксис для языка не являющегося хаскелм.
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[13]: Ликбез по ComputationExpressions
    От: lomeo Россия http://lomeo.livejournal.com/
    Дата: 28.04.10 20:40
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    L>>Ой, я не специалист. Сначала почитаю про то, что такое ComputationExpressions.

    VD>Монады переименованные для того чтобы не пугать гражданских и которым придан эдакий красивый синтаксис для языка не являющегося хаскелм.

    Прочитал (про F#) — это же один-в-один do-нотация. Если это та самая штука, то вопрос всё равно я не понял
    Re[11]: Ликбез по ComputationExpressions
    От: dsorokin Россия  
    Дата: 29.04.10 07:11
    Оценка:
    Здравствуйте, VladD2, Вы писали:

    VD> сделать сериализуемое ComputationExpressions


    Я тут покопался рефлектором. Оказывается, что компилятор F# генерирует функции (и замыкания ??) по возможности с атрибутом [Serializable] на уровне IL. Это означает, что во многих случаях можно попытаться сериализовать продолжение. То есть, всю последующую цепочку вычислений. И обернуть это в симпатичные computation expressions.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.