Определение области действия макроса let в emacs lisp - PullRequest
0 голосов
/ 05 мая 2018

В emacs lisp (но ответы, относящиеся к общему lisp, также приветствуются), у меня есть библиотека, в которой используется макрос, и я хочу перехватить один из аргументов макроса только при выполнении в определенном контексте. По сути, я хочу макрос:

; My macro. This is a sketch of what I want that doesn't work.
(defmacro hijack-f (body)
  `(macrolet ((f (x) `(f (+ 1 ,x))))
     ,@body))

; Defined in the library, I don't want to deal with these    
(defmacro f (x) x)
(defun g (x) (f x))

Так что

(g 1) ; => 1
(hijack-f (g 1)) ; => 2
(hijack-f (hijack-f (g 1))) ; => 3

EDIT: @melpomene и @ reiner-joswig правильно указывают, что f расширен в g до hijack-f. Как продолжение есть hijack-f такой, что:

(f 1) ; => 1
(hijack-f (f 1)) ; => 2
(hijack-f (hijack-f (f 1))) ; => 3

Ответы [ 2 ]

0 голосов
/ 05 мая 2018

Если вы счастливы, что f является функцией, а не макросом, и используете CL, а не elisp, то вам нужен flet и такой макрос:

(defmacro hijack-f (&body body)
  `(flet ((f (x)
            (f (1+ x))))
     ,@body))

Учитывая глобальное определение f:

(defun f (x)
  x)

Тогда

> (hijack-f (f 1))
2

> (hijack-f (hijack-f (f 1)))
3

и т. Д.

(Как уже отмечали другие, вы не можете перехватить код, который уже был скомпилирован с помощью макроса, подобного этому: вам нужно будет сделать это, если f будет сотрудничать в угоне.)

0 голосов
/ 05 мая 2018

Насколько я знаю, то, что вы хотите, невозможно, потому что g не содержит вызова f. Вместо этого f запускает first и расширяет (частично) определение g.

То есть:

(defun g (x) (f x))

немедленно превращается в

(defun g (x) x)

Который затем определяет g как функцию (значение которой (lambda (x) x)).

Неверное обращение с f во время выполнения ни на что не влияет, потому что его вызов давно ушел к тому времени, как вы вызываете g.

...