Как написать макрос схемы MIT для возврата лямбда-формы? - PullRequest
8 голосов
/ 12 октября 2011

Я сбит с толку, пытаясь создать эквивалент этого тривиального (в Common Lisp) макроса в схеме MIT:

(defmacro funcify (exp)
    `(lambda (x) ,exp))

Это простой персональный проект, решатель числовых уравнений, основанный нафункции встроены во второй лекции SICP.Мне все равно, что этот макрос не является "безопасным" или "гигиеническим" или будет захватывать переменную, если exp ссылается на любые символы, кроме 'x.Я хотел бы иметь возможность написать

(solv '(* 60 x) '(* 90 (- x 1)))

, где solv:

(define (solv lh-exp rh-exp)
    (solve (funcify lh-exp) (funcify rh-exp)))

вместо необходимости набирать

(solve (lambda (x) (* 60 x)) (lambda (x) (* 90 (- x 1))))

Но не могу понятькак это сделать, используя синтаксические правила MIT Scheme.

Я пробовал это, но это не работает:

(define-syntax funcify
  (syntax-rules ()
    ((funcify y) (lambda (x) y))))
;Value: funcify

(funcify x)
;Value 17: #[compound-procedure 17]

((funcify x) 10)
;Unbound variable: x

Я пробовал другие вещи, которые, вероятно, не стоит упоминатьeval но безрезультатно.

Кроме того, ссылки на хорошие учебные пособия (не ссылки) по макросистеме Схемы, которые начинаются с небольших простых примеров и строятся с достаточным количеством комментариев и, в частности, показывают, как преобразовать обратную цитатуМакросы LISP в стиле запятой (которые для меня очень интуитивно понятны) для макросовой системы синтаксиса Схемы были бы великолепны.

Ответы [ 2 ]

7 голосов
/ 12 октября 2011

Это не может быть сделано в syntax-rules. Конец истории.

Внедрение произвольного идентификатора (x, в вашем случае) в выходное выражение требует нарушения гигиены, а syntax-rules не предоставляет никаких средств для нарушения гигиены. Вам нужно будет использовать макро-систему более низкого уровня, чтобы сделать это. Схема MIT использует явное переименование (см. Ответ Матиаса Бенкара), но для других реализаций Схемы, использующих syntax-case, вы можете сделать это следующим образом:

(define-syntax funcify
  (lambda (stx)
    (syntax-case stx ()
      ((_ body)
       (with-syntax ((x (datum->syntax stx 'x)))
         #'(lambda (x)
             body))))))

Ключ - это бит (datum->syntax stx 'x), который вводит символ x, как если бы он находился в синтаксическом контексте вызова funcify.

Кстати, ваш solv также должен быть макросом, а не процедурой, но по крайней мере это может быть макрос syntax-rules:

(define-syntax solv
  (syntax-rules ()
    ((_ lhs rhs) (solve (funcify lhs) (funcify rhs)))))
4 голосов
/ 12 октября 2011

Вы можете сделать то же самое, что и с defmacro, используя макросы с явным переименованием . Единственное существенное отличие состоит в том, что вам придется самостоятельно деформировать форму ввода:

(define-syntax funcify
  (er-macro-transformer
    (lambda (form rename cmp)
      (let ((exp (cadr form)))
        `(,(rename 'lambda) (x) ,exp)))))
...