У меня есть реализация Scheme, и сейчас я тестирую макросы Hygieni c. У меня есть макрос -->
, который работает так:
(--> document (querySelector "body"))
, который просто вызовет JavaScript
document.querySelector("body")
, и я хочу создать макрос, который будет создавать макрос, который будет вызывать методы на объектах. Поэтому, если я использую:
(define-method document querySelector)
, это создаст функцию:
(define-macro (querySelector . args)
`(--> document (querySelector ,@args))
Это легко в макросах Lisp, потому что у меня есть @, чтобы склеить аргументы. Пример:
(define-macro (define-method object method)
(let ((args (gensym)))
`(define-macro (,method . ,args)
`(--> ,',object (,',method ,@,args)))))
Это можно проверить с помощью my Scheme Interpreter на Codepen .
Ниже приведен простой макрос в CommonLisp, который генерирует макросы, отображающие текст (мой макрос тестирования в Clisp)
(define-macro (make-printer name)
`(define-macro (,name)
`(let ((,',name "xxx"))
(write ,',name))))
это просто пример использования ,',
, которое я тестировал. Это создает бесполезный макрос, который выдает «xxx».
Я думал, что для решения этой проблемы мне нужно создать макрос, который будет создавать макрос.
(define-syntax define-method
(syntax-rules ()
((_ obj method)
(define-syntax method
(syntax-rules ()
???)))))
Проблема в том, что я могу создать функцию потому что я не могу использовать apply для вызова метода объекта. Это должен быть вызов функции. Я также не могу изменить макрос -->
, чтобы разрешить использование apply, потому что кто-то может захотеть вызвать метод apply для объекта, подобного
(--> fn (apply null '(1 2 3))
Рабочий пример:
(--> display (apply (current-environment) '#((1 2 3))))
он вызывает Function.prototype.apply
со средой и массивом / вектором из одного элемента списка. То же самое, что и (display '(1 2 3))
Чтобы сделать это 100% -ной проблемой схемы, я могу подумать об этом случае, у меня есть макрос, который принимает переменное число аргументов, и я хочу создать макрос, который создаст оболочку для этого макроса.
Например: у меня есть макрос (foo name . args)
, и я хочу создать макрос make-foo, который будет создавать макросы, которые вызывают foo. (make-foo get-name) должен создать макрос (get-name . args)
, который расширится до (foo 'get-name . args)
. И foo может быть определено как:
(define-syntax foo
(syntax-rules ()
((_ args ...)
(display '(args ...)))))
(define-syntax make-foo
(syntax-rules ()
((_ name)
(define-syntax name
(syntax-rules ()
((_ args ...)
(foo name args ...)))))))
(make-foo hello)
(hello 1 2 3)
А что если я захочу создать макрос Scheme Hygieni c, где имя будет foo-hello
, если я передам hello
. Возможно ли что-то подобное с syntax-rules
? Или мне нужно использовать макросы lisp или синтаксис-кейс. Я предпочитаю, если возможно, иметь код R5RS.
Я также пытался это сделать, чтобы иметь возможность создать функцию с переменным числом аргументов и создать макрос, который будет генерировать функцию с такими же аргументами:
(define (bar . args)
(for-each display args))
(define-syntax caller
(syntax-rules ()
((_ method)
(define (method . args)
(bar . args)))))
(caller foo)
(foo 1 2 3)
но это не работает, проверено в Кава и Гиль.