在Lisp中读取外部嵌套表单?
有没有办法做到这一点:在Lisp中读取外部嵌套表单?,lisp,common-lisp,Lisp,Common Lisp,有没有办法做到这一点: (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))
(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
来完成,但是,如果这样做会产生太多的开销,我将不得不找到另一个解决方案。谢谢。不,默认情况下不可能。这样做需要一些高级代码,而且不太容易:
- 自定义计算器
- 注入必要代码的代码行者
- 自定义计算器
- 注入必要代码的代码行者
- 否默认情况下不可能。这样做需要一些高级代码,而且不太容易:
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))
我一直在胡闹,想出了这个主意。这不完全是你想要的,但很接近。可以重命名
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))
我认为雷纳基本上是正确的,但我还是忍不住尝试用“宏扩展钩子”或读者方法来实现你的目标。无论哪种情况,我都不会从当前表单中删除(获取外部表单),但这应该是简单的列表操作 首先是读者方法。使用一个函数包装开括号读取器,该函数在调用默认开括号读取器的结果中搜索(获取外部形式)
;(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
第二,一种“宏扩展挂钩”方法。在窗体进行宏扩展之前,在窗体中查找(获取外部窗体)
;(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>
;(包装内| cl用户|)
(defun获取外部形式()
(错误“获取外部窗体仅从宏内部工作”))
获取外部形式
;(包装内| cl用户|)
(defvar*当前表单值*())
*当前形式值*
;(包装内| cl用户|)
(拆卸mhook(膨胀机形式环境)
(让*((见())
(固定的(如有必要,则替换)
(λ(x)
(当(equalp x'(获取外部形式))
(setq(见t)))
表格))
(看到时(setq*当前形式值*形式))
(funcall扩展器固定环境)
姆胡克
;(包装内| cl用户|)
(setq*宏扩展钩子*#'mhook)
#
我认为雷纳基本上是正确的,但我还是忍不住尝试使用*MacroExpandHook*或reader方法来实现您的目标。无论哪种情况,我都不会从当前表单中删除(获取外部表单),但这应该是简单的列表操作
首先是读者方法。使用一个函数包装开括号读取器,该函数在调用默认开括号读取器的结果中搜索(获取外部形式)
;(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
第二,一种“宏扩展挂钩”方法。在窗体进行宏扩展之前,在窗体中查找(获取外部窗体)
;(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>
;(包装内| cl用户|)
(defun获取外部形式()
(错误“获取外部窗体仅从宏内部工作”))
获取外部形式
;(包装内| cl用户|)
(defvar*当前表单值*())
*当前形式值*
;(包装内| cl用户|)
(拆卸mhook(膨胀机形式环境)
(让*((见())
(固定的(如有必要,则替换)
(λ(x)
(当(equalp x'(获取外部形式))
(setq(见t)))
表格))
(看到时(setq*当前形式值*形式))
(funcall扩展器固定环境)
MHOOK
;(包装内| cl用户|)
(setq*宏扩展钩子*#'mhook)
#
您是否在寻找某种方法来设置*当前表单值*
,将最外层的代码设置为数据或函数?你到底想用这个解决什么?抱歉,刚跑完回来。数据,此时我不想说:)您是否在寻找某种方法来设置*当前表单值*
,将最外层的代码设置为数据或函数?你到底想用这个解决什么?抱歉,刚跑完回来。数据,我不想说在这个时候:)自定义计算器,我得到,实现它。。。你能解释一下代码行者的部分吗?我得到的自定义计算器,实现它。。。你能解释一下代码行者的部分吗?我在考虑一个宏解决方案,这看起来很像我想要的,但是我需要使它更一般,我必须捕获它遇到的任何函数形式(let,lambda,+,…)。我也会努力的。谢谢我在考虑一个宏解决方案,这看起来很像我想要的,但是我需要使它更一般,在这种情况下,我必须捕获它遇到的任何函数(let,lambda,+,…)。我也会努力的。谢谢我在几个小时前看到了这一点,不得不去HyperSpec了解代码在做什么。。。不得不说,我印象深刻。我可能会使用reader示例,因为我计划扩展功能。两个代码段都适合使用!谢谢。刚刚弄清楚你在做什么,subst if和prog1,很好。我几个小时前看到了这个,不得不去HyperSpec看看代码在做什么。。。不得不说,我印象深刻。我可能会使用reader示例,因为我计划扩展功能。两个代码段都适合使用!谢谢,我刚刚知道你在做什么了,很好。