?

Log in

No account? Create an account

scala.meta: новая платформа для метапрограммирования Скалы - Excelsior

Jul. 5th, 2014

12:16 am - scala.meta: новая платформа для метапрограммирования Скалы

Previous Entry Share Next Entry

Comments:

From:Valentin Budaev
Date:July 11th, 2014 05:09 pm (UTC)
(Link)
А не было мысли сделать некий аналог syntax-local-value из racket? Тогда оба варианта можно реализовать в виде сахара. Ну и кроме того подход racket с макросами-структурами, у которых определен prop:procedure, будет выглядеть намного красивее в языке с ООП в ядре.
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:July 11th, 2014 07:07 pm (UTC)
(Link)
А где можно почитать про syntax-local-value? В документации не очень много деталей по этому поводу.
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:July 12th, 2014 12:14 am (UTC)
(Link)
(syntax-local-value syntax-id) просто возвращает значение макроса, то есть в обычном случае ф-ю из syntax в syntax, но в общем мы же можем в макрос положить все что угодно, вот примерчик
http://pastebin.com/s6GJsyEh


Edited at 2014-07-12 12:17 am (UTC)
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:July 12th, 2014 06:44 am (UTC)
(Link)
Спасибо! А как это работает с раздельной компиляцией?
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:July 12th, 2014 08:57 am (UTC)
(Link)
А никак, очевидно, это так называемый "3-D syntax", и раздельная компиляция с ним невозможна. Если хочется компилировать, то надо делать work around, окружая несереализуемые значения евалом, например, то есть чтобы самой лямбды в коде не было, а была форма, которая при вычислении возвращает эту лямбду.

Тут еще надо отметить, что begin-for-syntax - это core-форма, она никуда не исчезает после экспанда и остается в скомпилированном коде. По-этому даже после компиляции можно выполнять формы 1 фазы. А вот с макросами такое уже не прокатывает - они просто раскрываются. По-этому если хочется выполнить сайд-эффект в макросе, то следует вместо того чтобы просто написать "code", добавить в экспанд макроса #'(begin-for-syntax code), ну или #'(define-syntaxes () (begin code (values)), что то же самое, но работает в локальном контексте.
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:July 12th, 2014 06:43 am (UTC)
(Link)
Как я понимаю, prop:procedure реализован при помощи define-for-syntax переменной, значение которое извлекается через syntax-local-value?
(Reply) (Parent) (Thread)
From:Valentin Budaev
Date:July 12th, 2014 09:14 am (UTC)
(Link)
define-for-syntax никак не извлекается - определенная define-for-syntax переменная имеет значения из фазы 1 (вычисляется в 1) и связана в фазе 1. Переменная определенная через define связана в фазе 0 и имеет значение из 0 (вычисляемое в 0). Переменная определенная через define-syntax (макрос) - связана в фазе 0 и имеет значение, вычисляемое в фазе 1, ее-то значение мы и можем получить через syntax-local-value, при этом мы квотим имя переменной. То есть форма (syntax-local-value #'id) выполняется в 1 фазе, id связано в 0 фазе, если мы напишем (syntax-local-value id), то id в 1 фазе unbound, но под темплейтом (#') фаза опускается, переменная становится связана и мы в первой фазе извлекаем значение из переменной нулевой фазы. В общем случае это невозможно, конечно (ведь переменных 0 фазы в 1 фазе "еще не существует"), но т.к. эта переменная особая (макрос) и значение ее вычисляется в 1 фазе, то мы можем его получить через этот work around.

А prop:procedure - это просто специальный интерфейс ф-й, ну как в скале трейт Function - если структура реализует этот prop:procedure, то ее инстансы могут использоваться везде в качестве ф-й. В частности, мы можем определить структуру с prop:procedur, в котором ф-я будет имет тип syntax->syntax и тогда инстансы такой структуры можно использовать в качестве макросов - но при этом этот инстанс будет не прсото ф-ей макросом, но еще и иметь доп. информацию (поля структуры, собственно)

Например, сама форма определения структуры (struct struct-name args ...) определяет struct-name как макрос (define-syntax struct-name ...) и именно кладет в struct-name инстанс структуры с определенным prop:procedure. Как ф-я-макрос (struct-name args ...) раскрывается в конструктор структуры struct-name, но если мы сделаем (syntax-local-value #'struct-name) то получим обычный инстанс стурктуры к полям которого имеем доступ, с-но в этих полях сеттеры/геттеры, информация о супер-структуре и т.д. - все доступно в 1 фазе из других макросов. С-но макрос match когда в паттерне видит какой-то id, то он проверяет - а не является ли этот id указанным инстансом и если да, то через syntax-local-value получает его поля и на основе этой информации генерирует код для разбора значения.
(Reply) (Parent) (Thread)