有没有办法做到这一点:
(let ((x 5)(y 7))
(get-outer-form) ;; 'get-outer-form would capture the entire LET expression
(* x y))
35 ;; value returned from LET
*current-form-value* ;; variable to hold the form
(let ((x 5))(y 7))(* x y)) ;; value of evaluating *current-form-value*
如果可以,伪代码就足够了。我天真地认为这必须用read
来完成,但是,如果由此产生的开销太多,我将不得不寻找另一种解决方案。感谢。
答案 0 :(得分:3)
默认情况下不可能。这样做需要一些高级代码,并且不太可能轻松工作:
答案 1 :(得分:3)
我一直在摆弄一下,想出了这个。这不是你想要的,但它很接近。它可以重命名let
并自己创建它就是你想要的。
(defmacro letc (p &body b)
(when (equal (car b) '(get-outer-form))
(setq b `((setf *current-form-value* '(let ,p ,@(cdr b))),@(cdr b))))
`(let ,p ,@b))
(letc ((x 5)(y 7))
(get-outer-form) ;; 'get-outer-form would capture the entire LET expression
(* x y))
;; ==> 35
*current-form-value*
;; ==> (let ((x 5) (y 7)) (* x y))
或者更简单。使用letc
表示您希望捕获它。
(defmacro letc (p &body b)
`(let ,p (setf *current-form-value* '(letc ,p ,@b)),@b)))
(letc ((x 5)(y 7))
(* x y))
;; ==> 35
*current-form-value*
;; ==> (letc ((x 5) (y 7)) (* x y))
它们都有嵌套问题:
(letc ((x 5)(y 7))
(letc ((a (+ x y)))
(* 2 a)))
;; ==> 24
*current-form-value*
;; ==> (let ((a (+ x y))) (* 2 a))
答案 2 :(得分:1)
我认为Rainer基本上是正确的,但我无法用* macroexpand-hook *或读者方法帮助尝试你的目标子集。在任何一种情况下,我都不会从当前表单中删除(get-outer-form),但这应该是简单的列表操作。
首先是读者的方法。使用在调用默认打开括号读取器的结果中搜索(get-outer-form)的函数包装打开的括号读取器。
;(in-package |cl-user|)
(defparameter *standard-readtable* (copy-readtable ()))
*STANDARD-READTABLE*
;(in-package |cl-user|)
(defvar *current-form-value* ())
*CURRENT-FORM-VALUE*
;(in-package |cl-user|)
(defun get-outer-form ()
())
GET-OUTER-FORM
;(in-package |cl-user|)
(defun get-outer-form-paren-reader (stream char &optional count)
(declare (ignore count))
(let* ((seen ())
(paren-reader
(get-macro-character #\( *standard-readtable*))
(form (funcall paren-reader stream char)))
(subst-if ()
(lambda (x)
;; never substitute, search only.
(prog1 ()
(when (equalp x '(get-outer-form))
(setq seen t))))
form)
(when seen
(setq *current-form-value* form))
form))
GET-OUTER-FORM-PAREN-READER
;(in-package |cl-user|)
(set-macro-character #\( #'get-outer-form-paren-reader)
T
第二,一个* macroexpand-hook *方法。在宏扩展之前,在表单中查找(get-outer-form)。
;(in-package |cl-user|)
(defun get-outer-form ()
(error "get-outer-form only works from within a macro"))
GET-OUTER-FORM
;(in-package |cl-user|)
(defvar *current-form-value* ())
*CURRENT-FORM-VALUE*
;(in-package |cl-user|)
(defun mhook (expander form env)
(let* ((seen ())
(fixed (subst-if ()
(lambda (x)
(when (equalp x '(get-outer-form))
(setq seen t)))
form)))
(when seen (setq *current-form-value* form))
(funcall expander fixed env)))
MHOOK
;(in-package |cl-user|)
(setq *macroexpand-hook* #'mhook)
#<Compiled-function MHOOK #x30200FC5BB1F>