在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示例,因为我计划扩展功能。两个代码段都适合使用!谢谢,我刚刚知道你在做什么了,很好。