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

Я сбит с толку, пытаясь создать эквивалент этого тривиального (в 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.

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

(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, но безрезультатно.

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


person Bogatyr    schedule 12.10.2011    source источник


Ответы (2)


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

(define-syntax funcify
  (er-macro-transformer
    (lambda (form rename cmp)
      (let ((exp (cadr form)))
        `(,(rename 'lambda) (x) ,exp)))))
person Matthias Benkard    schedule 12.10.2011
comment
@ ChrisJester-Young Спасибо за исправление ошибки. :) - person Matthias Benkard; 12.10.2011
comment
+1. Огромное спасибо. define-syntax совершенно сбивает с толку, но я подозреваю, что он очень мощный, я хотел бы изучить его получше, есть ли ссылки на то, чтобы ускорить его? Я принимаю ваш ответ, потому что он дает функцию, которая работает в схеме MIT, я также хотел бы принять ответ Криса, потому что он также указывает, что solv также должен быть макросом синтаксических правил. - person Bogatyr; 12.10.2011
comment
Принятый ответ на этот вопрос: stackoverflow.com/questions/3484094/ имеет ссылку на книгу с макросами схемы обучения глав на том уровне, который я ищу: cs.brown.edu/~sk/Publications/Books/ProgLangs/2007- 04–26 / главы 36 и 37 - person Bogatyr; 13.10.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)))))
person Chris Jester-Young    schedule 12.10.2011
comment
+1 Большое спасибо за ваш ответ и за указание на то, что solv тоже должен быть макросом. Макросы сложны для начала, но макросы синтаксиса схемы - *, вероятно, самая сложная вещь, которую я когда-либо видел в языке, и я программировал (в основном, blubs, но я написал диссертацию MS на CL) более 30 годы. - person Bogatyr; 12.10.2011
comment
@Bogatyr: Подождите, пока дойдете до продолжения. ;-) (Если серьезно, Scheme концептуально представляет собой довольно большой язык, несмотря на то, что спецификация R5RS умещается в пределах 50 страниц.) - person Chris Jester-Young; 12.10.2011