1

我有以下功能(我是 Lisp 的初学者):

(defun my-fun (a b)
    (my-commandsend-and-reply-macro (cmd)
      (:reply (ok result)
              (do-something a b result)))
)

其中 my-commandsend-and-reply-macro 是另一个程序员编写的宏。我无法修改它。

my-commandsend-and-reply-macro 将命令(在此示例中为 cmd)发送到服务器进程(它是用另一种编程语言编写的),然后等待它的回答。然后在宏中使用用户给定的“:reply part of the code”处理答案。列表(ok 结果)是一种模式,在宏中,destructuring-bind 解构并将答案的适当部分绑定到 ok 和 result(ok 只是一个标志)。在此之后,":reply part" 的其他用户给定的行被执行。(用于结果处理)

我想做以下事情:

1、向其他进程发送类似的命令(这样就可以了)

2,使用结果调用函数(如做某事)并使用其他一些参数,这些参数是 my-fun 的实际参数(这部分失败......)

我怎样才能做到这一点?我认为问题是在宏扩展之前没有评估 a 和 b,当宏扩展时 Lisp 搜索本地 a 和 b 但没有 a 或 b。有没有办法评估a和b?(因此宏可以将它们视为具体值)

这是宏定义:(由另一个程序员编写)

(defmacro* my-commandsend-and-reply-macro ((cmd &rest args) &body body)
`(progn
  (with-request-id ()
   (setf (gethash *request-id* *my-callbacks*)
         (lambda (status &rest status-args)
           (case status
             ,@(loop for (kind . clause) in body when (eql kind :reply)
                 collect 
                 (destructuring-bind 
                    ((status-flag &rest lambda-form-pattern) 
                                    &body action-given-by-user) clause
                   `(,status-flag
                      (destructuring-bind ,lambda-form-pattern status-args
                        ,@action-given-by-user))))
             ((error)
               (message "Error: %s" (elt (elt status-args 0) 1))))))
               (apply #'send-command-to-process *request-id* cmd args)))))

with-request-id 的定义:

(defmacro* with-request-id ((&rest vars) &body body)
  "Send `getid' to the server, and call `body' once the response
with the new ID has arrived. By then, global variable `*request-id*'
is bound to the latest request ID."
`(progn
  (when (not (server-is-running))
        (error "Server isn't running!"))
  (when *reqid-queue*
        (error "Some internal error occured. Please, restart the program!"))
  (lexical-let (,@(loop for var in vars
                       collect `(,var ,var)))
    (setf *reqid-queue* (lambda ()
                         (unwind-protect
                             (progn ,@body)
                           (setf *reqid-queue* nil)))))
  (get-id)))

并从其他进程获取 id:

(defun get-id ()
  (send-command-to-process 'getid))
4

2 回答 2

1

根本不看你的代码(道歉——没时间)---

a并由b 函数评估my-fun所有函数都从评估它们的参数开始——只有宏和特殊形式不一定评估它们的所有参数。

但是这些ab不会传递给宏——传递给它的唯一东西绑定到cmd. 你甚至没有cmd在你的函数中定义!

您需要做的是将和的替换为sexp. 您根本没有展示如何定义/构造。使用和的值构造它,你应该没问题。abcmdcmdab

要构造cmdsexp,请记住您可以使用反引号语法来简化事情,使用逗号语法来传递and的。例如ab

 (let ((cmd  `(some funny (expression) that ((uses)) ,a AND ,b)))
   code-that-uses-CMD)

这假定您传递给宏的代码不需要变量 ab,它只需要它们的

于 2013-10-26T16:15:34.113 回答
1

当函数my-fun被调用时,参数已经被评估,所以我不清楚你面临的问题是什么。

我看到的唯一奇怪的事情是宏不卫生,所以如果你的参数被命名而不是,a例如bstatus或者status-args你会遇到麻烦,因为表达式

(do-something <a> <b> results)

将在这些名称已被宏重用的上下文中编译。

于 2013-10-27T18:27:37.683 回答