Макрос LISP, который обрабатывает переменные и структуру данных внутри во время выполнения - PullRequest
0 голосов
/ 25 апреля 2019

У меня есть LISP, написанный на JavaScript (https://jcubic.github.io/lips/ с онлайн-демонстрацией, где вы можете попробовать его), и у меня есть макрос, подобный этому:

(define-macro (globalize symbol)
  (let ((obj (--> (. lips 'env) (get symbol))))
    `(begin
       ,@(map (lambda (key)
                (print (concat key " " (function? (. obj key))))
                (if (function? (. obj key))
                    (let* ((fname (gensym))
                           (args (gensym))
                           (code `(define (,(string->symbol key) . ,args)
                                    (apply (. ,obj ,key) ,args))))
                      (print code)
                      code)))
              ;; native Object.key function call on input object
              (array->list (--> Object (keys obj)))))))

В этом коде я использую это:

(let ((obj (--> (. lips 'env) (get symbol))))

и я вызываю этот макрос, используя:

(globalize pfs)

для создания функции для каждого статического метода pfs (который представляет собой LightingFS из isomorphic-git, где каждая функция возвращает обещание, это как fsиз узла).

Но это не сработает для чего-то подобного:

(let ((x pfs))
  (globalize x))

, потому что lips.env является глобальной средой.

Так что мой вопрос в том, как макросдолжно сработать?Должны ли они обрабатывать входные данные только как символы, чтобы они никогда не имели доступа к объекту до оценки кода lisp?

Как должен выглядеть макрос LISP, генерирующий набор функций на основе переменных.Например, в схеме, если у меня есть alist в переменной и я хочу сгенерировать функцию для каждой клавиши, которая будет возвращать значение:

input:

(define input `((foo . 10) (bar . 20)))

output:

(begin
  (define (foo) 10)
  (define (bar) 20))

Могу ли я написать макрос, который выдаст такой вывод, если я использую (macro input)?Или единственный вариант - (macro ((foo . 10) (bar . 20)))?

Я могу принять общий ответ Scheme или Common LISP, но, пожалуйста, не публикуйте макросы определения синтаксиса и гигиенические макросы из схемы, у моего lisp их нет и никогда не будет.

Проблема, кажется, в том, что я хочу получить доступ к значению во время раскрытия макроса, и оно должно иметь значение, которое во время выполнения.И второй вопрос eval в этом случае единственный вариант?

Это работает в biwascheme :

(define-macro (macro obj)
  (let ((obj (eval obj)))
    `(begin
       ,@(map (lambda (pair)
                (let ((name (car pair))
                      (value (cdr pair)))
                `(define (,name) ,value)))
              obj))))

(define input `((foo . 10) (bar . 20)))

(macro input)

(foo)
;; ==> 10
(bar)
;; ==> 20

(в моем lisp eval donне работает как в biwascheme, но это другая проблема).

но это не работает, потому что x не глобален:

(let ((x '((g . 10)))) (macro x))

Является ли макрос с eval тем, что вы обычно делаете,или их следует избегать?Есть ли другой способ генерировать набор функций на основе объекта времени выполнения.

1 Ответ

2 голосов
/ 26 апреля 2019

В Common Lisp: создание и компиляция функций во время выполнения.

CL-USER 20 > (defparameter *input* '((foo . 10) (bar . 20)))
*INPUT*

CL-USER 21 > (defun make-my-functions (input)
               (loop for (symbol . number) in input
                     do (compile symbol `(lambda  () ,number))))
MAKE-MY-FUNCTIONS

CL-USER 22 > (make-my-functions *input*)
NIL

CL-USER 23 > (foo)
10

CL-USER 24 > (bar)
20

Из локальной переменной:

CL-USER 25 > (let ((input '((foo2 . 102) (bar3 . 303))))
               (make-my-functions input))
NIL

CL-USER 26 > (bar3)
303

С макросом, более неуклюжим и ограниченным:

CL-USER 37 > (defparameter *input* '((foo1 . 101) (bar2 . 202)))
*INPUT*

CL-USER 38 > (defmacro def-my-functions (input &optional getter)
               `(progn
                  ,@(loop for (symbol . number) in (if getter
                                                       (funcall getter input)
                                                       input)
                          collect `(defun ,symbol () ,number))))
DEF-MY-FUNCTIONS

CL-USER 39 > (def-my-functions *input* symbol-value)
BAR2

CL-USER 40 > (foo1)
101
...