1

In Lisp, how do you call, from a macro, a function whose name is the symbol value of a symbol? I might be wrong but I think I'm right that a symbol is a variable.

Here is what I currently have:

(defmacro cfunc (a b) (list a b))
(defparameter foo 'my-func)
(defun my-func (data) '(some-code))
(cfunc foo data) ;does not work    
(cfunc my-func data) ;works

I'm thinking I need to add some special character in front of foo to evaluate to its symbol value before being treated as a function. (cfunc foo data) creates and calls the function (foo data) instead of (my-func data). I suppose I could change the function defining in cfunc instead.

#'foo doesn't work, that gives (function foo) which cfunc returns and calls ((function foo) data). (symbol-value foo) can't work either. So I'm thinking I can't change what is given to cfunc but I can change the code of the function cfunc makes.

If someone has a specific page of a resource that tells me about evaluation and expansion using defmacro or the specifics of the special characters like # and ' or know the keywords I should be looking up, I'd appreciate it if that could be shared as well.

1 Answer 1

2

First, in the form (cfunc foo data), to what do you expect that data refers? I don't see any definition of it here. It's only mentioned incidentally as a parameter to the my-func function, which doesn't come into play for your expansion of cfunc. Perhaps you expect data to be available later as a special variable.

In any case, the problem you're running into is that Common Lisp is a "Lisp-2"; a variable present at the head of a function form doesn't automatically have its function cell accessed to coerce it to a function. In your case, foo is not a function bound in the environment; it's a variable whose value is a symbol (my-func)—one that in turn is bound to a function. To navigate this extra level of indirection, you have to request that that symbol's function cell be accessed, either via funcall or, in other cases, function.

Here are a few observations from the REPL:

> (symbol-value 'foo)
MY-FUNC
> (ignore-errors (symbol-function 'foo))
NIL
#<UNDEFINED-FUNCTION FOO {1004E22D23}>
> (fboundp 'foo)
NIL

> (ignore-errors (symbol-value 'my-func))
NIL
#<UNBOUND-VARIABLE MY-FUNC {1005324E93}>
> (symbol-function 'my-func)
#<FUNCTION MY-FUNC>
> (fboundp 'my-func)
T

Here we see that the symbol foo has a value binding—meaning it's a variable—but it has no function binding. Following foo through to my-func, we see that my-func has no value binding, but it does have a function binding.

To wrap up, your cfunc macro needs be written as follows:

(defmacro cfunc (a b)
  (list 'funcall a b))

Alternately, you can write it like this:

(defmacro cfunc (a b)
  `(funcall ,a ,b))

You mentioned originally that the form

(cfunc my-func data)

works as intended. With my proposed revision above, it won't work any longer, because now my-func is being treated as a value to be evaluated as an argument to funcall, when in fact it has no value cell (as it's a function). Hence, you'll have to adapt the form to the following:

(cfunc #'my-func data)

That's saying, "Look up the symbol 'my-func' in the function namespace, grab its value, and supply that function as an argument."

For a more precise treatment on the difference in handling such symbols-pointing-to-functions in Lisp-1 and -2, see Gabriel's Technical Issues of Separation in Function Cells and Value Cells—in particular, section 5, "Notational Simplicity".

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a bunch, data just refers to the parameters for the function made by cfunc. So one problem was having the variable name as the first item in the list in cfunc and the second one was accessing the function value of the value of the symbol. foo has the value of my-func and my-func has the function value of the function I want
I revised the answer to use more precise language for things like bindings, variables, values, and functions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.