?

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 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)
From:Valentin Budaev
Date:August 29th, 2013 09:43 am (UTC)
(Link)
Была одна годная, но не могу сейчас найти, если найду, то дам ссылку.

Например, это используется в Racket в паттерн-матчинге по структурам - форма (struct struct-name ...) связывает со struct-name статическую информацию о свойствах структуры (гетеры, ацессоры, базовая структура и т.п.), потом когда мы делаем (match x [(struct-name ...) ...]), то match проверяет (статически, во время экспанда) - действительно ли struct-name структура, и, если да, то разбирает ее с помощью указанных в полученной информации геттеров.

Но тут все делается на ручном приводе, ага :)

А если сумеем трекать биндинги - то сможем автоматически туда-сюда гонять.

Edited at 2013-08-29 09:44 am (UTC)
(Reply) (Parent) (Thread)
[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)
[User Picture]
From:xeno_by
Date:August 29th, 2013 07:33 am (UTC)
(Link)
Сериализация нужна для поддержки раздельной компиляции. Если я написал квазицитату в отдельном модуле, скомпилировал ее, и прилинковался к ней из макроса в другом модуле, то я бы хотел, чтобы та квазицитата как-то запомнила свой оригинальный лексический контекст.
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:August 29th, 2013 08:57 am (UTC)
(Link)
Так смотрите, у вас либо идентификатор module-level (и тогда информации о контексте не нужно - нужен лишь полный квалификатор имени) либо она lexical - но тогда нет смысла использовать квазицитату в другом модуле - там ведь лексический контекст тоже будет другой и это будет гарантированная ошибка (то есть вы получается попытаетесь использовать идентификатор вне контекста, на который он ссылается.
(Reply) (Parent) (Thread) (Expand)
[User Picture]
From:xeno_by
Date:August 29th, 2013 08:25 am (UTC)
(Link)
Еще было бы интересно услышать ваше мнение насчет МП в D: http://xeno-by.livejournal.com/86554.html
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:August 29th, 2013 09:47 am (UTC)
(Link)
Ну, если макросистема хорошая, то все эти "alias, enum, template, и так далее [2, 3]" можно написать в виде макросов. :)
Это часть того, что я подразумевал под АПИ в своем ответе о недостатках TH. То есть если это частый юзкейс - ну выделить в отдельный слой АПИ, пусть люди не парятся с закатом солнца вручную. А если надо чего другого - ну есть другой слой АПИ, либо, если нету - то уже тогда руками можно.
(Reply) (Parent) (Thread)
[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)