1
votes

I have the following function (I am a very beginner at Lisp):

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

where my-commandsend-and-reply-macro is a macro written by another programmer. I am unable to modify it.

my-commandsend-and-reply-macro sends a command (in this example cmd) to a server process (it is written in another programming language) and then waits for its answer. The answer is processed then in the macro using the user-given ":reply part of the code". The list (ok result) is a kind of pattern, in the macro a destructuring-bind destructures and binds the proper parts of the answer to ok and result (ok is just a flag). After this the other user-given lines of the ":reply part" are excuted. (for result processing)

I would like to do the following:

1, send a command like to the other process (this is ok)

2, call a function (like do-something) using the result AND using some other parameters which are the actual parameters of my-fun (this part fails...)

How can I do this? I think the problem is that a and b are not evaluated before the macro expansion and when the macro is expanded Lisp searches for a local a and b but there is no a or b. Is there any way to evaluate a and b? (so the macro could treat them like concrete values)

This is the macro def: (written by another programmer)

(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)))))

Def of 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)))

And getting id from the other process:

(defun get-id ()
  (send-command-to-process 'getid))
2
You'd do far better to show the macro as well (or a demonstrative version thereof), rather than just trying to describe it. And I'm really not sure what this means: send a command like i (like do-something) n my-fun (this is ok)phils
I agree with @phils. Try to show what you have tried so far -- the exact code. Say what happens with it and what you expect/want to happen instead.Drew
As it is mentioned in my question, I tried to use "my-commandsend-and-reply-macro" and its ":reply" part defining my own callback function. In the callback I need to use some variables (see the example, like variable "a" and "b" of my-fun used in do-something). What happens: the variables aren't evaluated, and Lisp says that there is no variable "a" or "b" (maybe cause of dynamic scoping) because it searches for them where the macro is expanded. I would like to have a workaround for this.user1724641
What is defmacro*, in comparison with defmacro?Svante
Emacs gave the following (using the 'Describe' function): defmacro* is a Lisp macro. (defmacro* NAME ARGLIST [DOCSTRING] BODY...) Define NAME as a macro. Like normal `defmacro', except ARGLIST allows full Common Lisp conventions, and BODY is implicitly surrounded by (block NAME ...).user1724641

2 Answers

1
votes

Without looking into your code at all (apologies -- no time) ---

a and b are evaluated by the function my-fun. All functions evaluate their arguments to begin with -- only macros and special forms do not necessarily evaluate all of their arguments.

But those a and b values are not passed to the macro -- the only thing passed to it is the unevaluated sexp that is bound to cmd. And you do not even define cmd in your function!

What you need to do is substitute the values of a and b into the cmd sexp. You have not shown how cmd is defined/constructed, at all. Construct it using the values of a and b, and you should be OK.

To construct the cmd sexp, remember that you can use backquote syntax to simplify things, using comma syntax to pass the values of a and b. E.g.

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

This assumes that the code you pass to the macro does not need the variables a and b, and it needs only their values.

1
votes

When the function my-fun is called the arguments have already been evaluated so it's not clear to me what is the problem you are facing.

The only strange thing I see is that the macro is un-hygienic and so if your arguments are named instead of a and b for example status or status-args you're going to be in trouble because the expression

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

will be compiled in a context where those names have been reused by the macro.