Search code examples
macroslispcommon-lispelispmetaprogramming

Defining a let macro scope in emacs lisp


In emacs lisp (but answers relating to common lisp are also welcome) I have a library that uses a macro and I want to hijack one of the macro's arguments only when executed in a certain context. Essentially what I want is a macro:

; 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))

So that

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

EDIT: @melpomene and @reiner-joswig correctly point out that f is expanded in g before hijack-f. As a followup is there a hijack-f such that:

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

Solution

  • As far as I know, what you want is not possible because g does not contain an invocation of f. Instead f runs first and expands to (part of) the definition of g.

    That is:

    (defun g (x) (f x))
    

    immediately turns into

    (defun g (x) x)
    

    Which then defines g as a function (whose value is (lambda (x) x)).

    Messing with f at runtime doesn't affect anything because its invocation is long gone by the time you call g.