在Lisp中读取外部嵌套表单?

时间:2014-03-29 14:13:05

标签: 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)) ;; value of evaluating *current-form-value*

如果可以,伪代码就足够了。我天真地认为这必须用read来完成,但是,如果由此产生的开销太多,我将不得不寻找另一种解决方案。感谢。

3 个答案:

答案 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>