?

Log in

No account? Create an account

Метапрограммирование в Агде и немного философии - Excelsior

Aug. 27th, 2013

09:49 am - Метапрограммирование в Агде и немного философии

Previous Entry Share Next Entry

Comments:

From:Valentin Budaev
Date:August 27th, 2013 10:31 pm (UTC)
(Link)
Ну вот. Откуда возьмется формализация, когда нечего формализовывать? :)

А немерлисты со своим немерле 2 вообще ушли не в те степи. Изначальная идея (объединить экспанд с тайпчеком) вроде и годна, но в результате у них получается какой-то ОБЧР с пиу-пиу лазерами из глаз и торчащим во лбу тентаклем, а не макросистема.

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

А на текущем уровне не ясно, в какую сторону идти. Никто никуда и не идет :)
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:August 27th, 2013 10:41 pm (UTC)
(Link)
Будем стараться! Вот буквально сейчас думаем над тем, как именно прикрутить гигиену. Есть несколько вариантов - как минимум пути Схемы, Немерле и Темплейт Хаскелла. Плюс, еще есть вариант на ручной тяге, но его не считаем. У всех есть свои трейд-оффы и свои сложности в реализации, поэтому поступало даже предложение забить на гигиену, но сейчас не время для малодушия :)
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:August 27th, 2013 11:29 pm (UTC)
(Link)
> Вот буквально сейчас думаем над тем, как именно прикрутить гигиену.

Не забудьте сразу подумать об удобных путях обхода и средствах "обхода гигиены без ее нарушения" (http://www.schemeworkshop.org/2011/papers/Barzilay2011.pdf), оно покрывает большую часть юзкейсов обхода.

Вот с этой статьей знакомы, кстати: http://www.ccs.neu.edu/home/dherman/research/papers/esop08-hygiene.pdf ?
И более подробно в диссертации: http://www.ccs.neu.edu/home/dherman/research/papers/dissertation.pdf

В nemerle, кстати, вполне схемная гигиена, конкретно - как в Racket (привязка идентификатора к контексту). И это единственный правильный путь, на мой взгляд. Вариант с TH (а также явные ренейминги и т.п.) кажется ограниченным - непонятно, как лифтануть идентификатор из контекста в контекст. Хотя может я просто плохо знаю TH.
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:August 28th, 2013 06:05 am (UTC)
(Link)
Про формализацию гигиены слышал, но пока что не добрался. Сейчас надо будет, конечно. Спасибо!
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:August 28th, 2013 11:29 am (UTC)
(Link)
Обратите внимание, что проблема важнее, чем кажется. Если мы научимся коректно трекать биндинги - то мы сразу научимся корректно распространять статическую информацию довольно произвольного вида, тем же путем. А это уже _намного_ интереснее.
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:August 29th, 2013 05:45 am (UTC)
(Link)
А на эту тему есть какие-нибудь паперы? (Я имею ввиду про распространение произвольной статической информации)

Edited at 2013-08-29 05:45 am (UTC)
(Reply) (Parent) (Thread) (Expand)
[User Picture]
From:xeno_by
Date:August 28th, 2013 06:07 am (UTC)
(Link)
Кстати, знакомы ли вы с реализацией гигиены в Ракете? А именно с тем, как они сохраняют лексический контекст для идентификаторов.

Мне пока не приходит в голову ничего умнее, чем запоминать: 1) весь исходный файл (только один файл, не весь проект), в котором определена квазицитата, 2) позицию квазицитаты в исходнике.
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:August 28th, 2013 11:28 am (UTC)
(Link)
> Кстати, знакомы ли вы с реализацией гигиены в Ракете?

Про алгоритм гигиены я ниже рассказал, ну там надо просто потыкать в экспандере и будет все понятно :)

А вот именно с тем как привязывается к идентификаторам лексический контекст и как с ним работают (в частности, как работают let-формы, partial-expand в internal definitions и т.п.) - это какое-то страшное колдунство. По идее, можно самому руками устанавливать связывания (и реализовывать let-формы низкоуровнево, то есть связывать переменные, не раскрывая макрос в define/let-форму), но в доках описано мало и криво. Я все собирался порыться в исходник и разобраться, что да как - но так руки и не дошли.

> 2) позицию квазицитаты в исходнике.

В racket работают с source object - который, в частности, имеет source location. Вам в любом случае нужно будет рано или поздно этот source location для квазицитат (и подобъектов) устанавливать - иначе будет большая беда с обработкой ошибок в макрах.

Что до контекстов - как я понимаю, там просто во время экспанда, когда видим let-форму, то создаем контекст, который содержит связанные переменные (когда видим define - добавляем идентификатор в контекст модуля), контексты могут друг в друга вкладываться, сами идентификаторы содержат ссылки на контекст, соответственно. По крайней мере, глядя на ихнее АПИ, все должно примерно так быть.

Или вы про сериализацию контекстов? А зачем оно?
(Reply) (Parent) (Thread) (Expand)
[User Picture]
From:xeno_by
Date:August 29th, 2013 07:33 am (UTC)
(Link)
Сериализация нужна для поддержки раздельной компиляции. Если я написал квазицитату в отдельном модуле, скомпилировал ее, и прилинковался к ней из макроса в другом модуле, то я бы хотел, чтобы та квазицитата как-то запомнила свой оригинальный лексический контекст.
(Reply) (Parent) (Thread) (Expand)
[User Picture]
From:xeno_by
Date:August 28th, 2013 06:13 am (UTC)
(Link)
В Немерле есть интересный хак. Локальные переменные в квазицитатах не запоминают свой лексический контекст:
  import Bar;
  def d1 = <[ def x = y + foo(4) ]>;
  def d2 = <[ def y = $(Bar.Compute(): int) ]>;
  <[ 
    $d2;
    def foo(x) { x + 1 }; 
    $d1;
    x * 2 
  ]>
Насколько я понимаю, Bar тут прибиндится к заимпортированному имени, а вот y и foo нарушат ссылочную прозрачность, т.е. даже если перед def d1 = ... определить def y = 100500, это ничего не изменит.
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:August 28th, 2013 11:37 am (UTC)
(Link)
В scheme есть вообще разные подходы, к тому, когда случается clash переменных в разных квазицитатах. Первый - когда все переменные с одним именем, сгенеренные в рамках одного трансформера, "одинаковы", то есть (define x-arg #'x) #`(let ([x 1]) #,x-arg) - работает (если эти формы в одном макросе идут), а второй - когда они разные, то есть в описанном случае будет unbound variable, и связать вводимую квазицитатой переменную можно только в той же квазицитате (если не обойти гигиену руками, конечно). Обычно используется первый - он, в общем, удобнее. Второй более безопасен. Но я, кстати, даже не припомню, где использовался второй.

Edited at 2013-08-28 11:37 am (UTC)
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:September 8th, 2013 06:58 am (UTC)
(Link)
А что вы думаете про гигиену в Clojure? [1] Похоже, что там квазицитаты referentially transparent (т.е. биндинги к top-level идентификаторам сохраняются), но не hygienic.

[1] https://groups.google.com/d/msg/scala-language/7h27npd1DKI/vuVB5KYFX0QJ

Edited at 2013-09-08 10:26 am (UTC)
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:September 30th, 2013 02:37 pm (UTC)
(Link)
Есть вопрос насчет syntax parameters.

Скажем, есть вот такой код из официальной документации ракета:
> (define-syntax-parameter it (syntax-rules ()))
> (define-syntax aif
    (syntax-rules ()
      [(aif test then else)
       (let ([t test])
         (syntax-parameterize ([it (syntax-id-rules () [_ t])])
           (if t then else)))]))
И после такого определения, насколько я понимаю, можно писать что-то вроде (aif expr it it) и it будет ссылаться на результат вычисления expr. Все это без ручного нарушения гигиены, что прекрасно. Но что если пользователь хочет переименовать it в it2? Будет ли у него такая возможность?
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:August 27th, 2013 10:43 pm (UTC)
(Link)
А что там с тентаклем? Я, если честно, особо не следил за последними событиями в N2. Есть ли там что-то новое, что вы имеете ввиду, или же вам в целом не нравится предложенный фреймворк для тайпчека?
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:August 27th, 2013 11:16 pm (UTC)
(Link)
Мне не нравится универсальность, которой они хотят добиться, сделать вроде как "фреймоврк для разработки типизированных ЯП". Понятно, что в достаточно выразительной макросистеме можно навернуть все что угодно поверх хост-языка - но обычно эта возможность больше теоретическая и на практике стоит больших трудозатрат. А когда постулируется что "наша система удобно решает любую задачу", то это на практике значит, что она все задачи решает одинаково неудобно. Но, конечно, может и что-то удачное получиться вы итоге - заранее тут не скажешь.
(Reply) (Parent) (Thread)