LINUX.ORG.RU

История изменений

Исправление dave, (текущая версия) :

Мне больше нравятся контролируемые продолжения. Например, мы говорим, что продолжения могут быть только внутри with-call/cc и/или defun/cc. Только там будет оверхед. Все остальное работает как прежде. Этот подход отличается от принятого в Scheme. Он используется в cl-cont.

Фишка с вычислительными выражениями в том, что не нужно вводить специальную поддержку именно для продолжений. Можно преобразовывать код (через code-walker) для произвольных монад и моноидов. Да, там будет до черта накладных расходов. Да, не будет многих оптимизаций. Но такой код будет строго ограничен рамками with-call/cc или его обобщенного аналога.

Собственно, это и происходит уже сейчас при использовании cl-cont, но он неэффективно раскрывает циклы. Для эффективного раскрытия какие-то примитивы циклов должны были бы быть подняты до уровня специальных форм, как это, грубо говоря, сделано в f#.

Чтобы раскрыть форму unwind-protect, можно было бы завести второе продолжение, которое следовало бы передавать в каждую часть вычисления наряду с основным продолжением. Именно это происходит в f# async при обработке try-finally. Совершенно неясно только, что делать с handler-bind и handler-case, хотя в f# обрабатывается try-with (аналог handler-case). Это все мысли относительно гипотетической лисп-системы, использующей приспособленные для этого специальные формы. Здесь я считаю, что это просто случайное совпадение, что cl-cont уже сейчас умеет раскрывать почти все специальные формы, за исключением unwind-protect и той, что отвечает за handler-bind / handler-case (кажется, первая форма специальная, а вторая - производная).

Умея раскрывать unwind-protect и handler-case, можно было бы закрывать своевременно и файлы, и сокеты. Кстати, в f# есть дополнительная конструкция use! наряду с просто use. Они вполне дружат с async: там можно управлять ресурсами в рамках асинхронного вычисления, построенного фактически на продолжениях (хотя у меня возникали странные баги в редких случаях).

В общем, идея в том, что специальные формы должны быть подобраны таким образом, чтобы после преобразования (будь то монада async или моноиды seq, list, array) сохранялась бы строгая модель исполнения, а также была бы возможность управлять ресурсами. Все это уже реализовано в f#. Только я не представляю себе, как это должно и может ли сосуществовать с рестартами и динамическими переменными. Вполне возможно, что не может, и ничего уже не сделать лучше, чем есть сейчас в common lisp. В некотором смысле, идеал уже, быть может, достигнут.

Исходная версия dave, :

Мне больше нравятся контролируемые продолжения. Например, мы говорим, что продолжения могут быть только внутри with-call/cc и/или defun/cc. Только там будет оверхед. Все остальное работает как прежде. Этот подход отличается от принятого в Scheme. Он используется в cl-cont.

Фишка с вычислительными выражениями в том, что не нужно вводить специальную поддержку именно для продолжений. Можно преобразовывать код (через code-walker) для произвольных монад и моноидов. Да, там будет до черта накладных расходов. Да, не будет многих оптимизаций. Но такой код будет строго ограничен рамками with-call/cc или его обобщенного аналога.

Собственно, это и происходит уже сейчас при использовании cl-cont, но он неэффективно раскрывает циклы. Для эффективного раскрытия какие-то примитивы циклов должны были бы быть подняты до уровня специальных форм, как это, грубо говоря, сделано в f#.

Чтобы раскрыть форму unwind-protect, можно было бы завести второе продолжение, которое следовало бы передавать в каждую часть вычисления наряду с основным продолжением. Именно это происходит в f# async при обработке try-finally. Совершенно неясно только, что делать с handler-bind и handler-case, хотя в f# обрабатывается try-with (аналог handler-case). Это все мысли относительно гипотетической лисп-системы, использующей приспособленные для этого специальные формы. Здесь я считаю, что это просто случайное совпадение, что cl-cont уже сейчас умеет раскрывать почти все специальные формы, за исключением unwind-protect и той, что отвечает за handler-bind / handler-case (кажется, первая форма специальная, а вторая - производная).

Умея раскрывать unwind-protect и handler-case, можно было бы закрывать своевременно и файлы, и сокеты. Кстати, в f# есть дополнительная конструкция use! наряду с просто use. Они вполне дружат с async: там можно управлять ресурсами в рамках асинхронного вычисления, построенного фактически на продолжениях (хотя у меня возникали странные баги в редких случаях).

В общем, идея в том, что специальные формы должны быть подобраны таким образом, чтобы после преобразования (будь то монада async или моноиды seq, list, array) сохранялась бы строгая модель исполнения, а также была бы возможность управлять ресурсами. Все это уже реализовано в f#. Только я не представляю себе, как это должно и может ли сосуществовать с рестартами и динамическими переменными. Вполне возможно, что не может, и ничего уже не сделать лучше, чем есть сейчас в common lisp. В некотором смысле, идеал уже достигнут.