Я пытаюсь написать макрос Behaving так же, как рэкет определить, но обработки полностью укомплектованные процедуры ракетки какими-то образом (только расширение для упрощения в примере ниже):Ракетки: локальные расширяющиеся рекурсивные определения
(define-syntax (define/expand stx)
(syntax-case stx()
[(_ (head args ...) body body-rest ...)
(let* ([define/racket (syntax/loc stx (define (head args ...) body body-rest ...))]
[fully-expanded (local-expand define/racket 'top-level (list))])
fully-expanded)]
[(_ id expr) (syntax/loc stx (define id expr))]))
Все хорошо, если рекурсивное определение не будет выполнено:
(define/expand (sum n)
(if (<= n 0)
0
(+ n (sum (- n 1)))))
Забегая вызывает ошибку
сумму: unbou го идентификатора модуля в: сумма
указывая вызов из sum
(не определение). Очевидно, что определение sum
не фиксируется локальным расширителем. Я попытался простым способом ее фиксации: создание нового контекста локального определения и связывание head
в него:
(define-syntax (define/expand stx)
(syntax-case stx()
[(_ (head args ...) body body-rest ...)
(let* ([ctx (syntax-local-make-definition-context)] ; <- These two lines added
[_ (syntax-local-bind-syntaxes (list #'head) #f ctx)] ; <--/
[define/racket (syntax/loc stx (define (head args ...) body body-rest ...))]
[fully-expanded (local-expand define/racket 'top-level (list) ctx)])
fully-expanded)]
[(_ id expr) (syntax/loc stx (define id expr))]))
Это решает проблему (локальный расширены успешно расширяет процедуру в define-values
), но создает другую:
модуля: вне контекста идентификатора для определения в: сумме
указывая определения суммы. Причина в том, что расширитель связывает идентификаторы с одним в ctx
вместо head
в текущем контексте.
Интуитивно это не похоже на редкую проблему, но я не смог найти решение по сети. Я думал, что мне нужно как-то использовать local-expand/capture-lifts
и syntax-local-lift-expression
, но я не понимаю, как правильно его использовать. Может ли кто-нибудь уточнить, что происходит и/или дать подсказку, как это исправить?
Другой порой полезный трюк: позвонить Локаль--expand' на лямбда связывания несвязанных переменных, а затем сопоставления с образцом результат, чтобы вывести организм. –