我正在尝试查看数据与代码替换在使用eval
之类的函数时如何工作,该函数允许我传递任何打印命令,如print
princ
等一些文本,它在输出中使用该命令:
(defun print-test (fn text)
(eval '(fn 'text)))
我尝试了各种各样的方法,但我不能让它运行。我也尝试过:
(defun print-test (fn text)
(eval ('fn 'text)))
..和其他变化。所以我显然错过了一些东西。我希望能够做到这一点:
(print-test 'princ 'some-text)
我通常会收到错误fn is undefined
。但是,由于我正在实时评估代码,我认为它可以从我的输入中得到fn
?
我意识到还有其他方法可以做到这一点,比如传入像#'princ
这样的实际函数对象,但我很好奇eval
机制如何动态生成代码。
答案 0 :(得分:3)
fn is undefined
之类的错误并未告诉您princ
未定义,但符号fn
没有函数绑定。您不想调用符号fn
,而是要调用变量fn
的值。
看起来您想要评估一个列表,其第一个元素是fn
的值,第二个元素是text
的值。您可以使用list
中的(list fn text)
函数创建此类列表。然后你可以用它来呼叫eval
:
(defun print-test (fn text)
(eval (list fn text)))
您也可以使用反引号表示法,并执行
(defun print-test (fn text)
(eval `(,fn ,text)))
在这些情况下,如果您希望与(princ 'hi)
具有相同的效果,则需要fn
作为符号princ
并text
作为列表 'hi
(是的,列表,因为'hi
是(quote hi)
的简写)。你会这样打电话,然后:
(print-test 'princ ''hi)
如果第二个参数总是在生成的文本中引用,您还可以选择以下任何一个:
(eval `(,fn ',text))
(eval `(,fn (quote ,text)))
(eval (list fn (list 'quote text)))
尽管如此,这似乎是一种使用eval
的非常奇怪的方式。除非有一些特别好的理由,为什么不使用funcall
?毕竟,如果fn
作为要评估的表单的汽车是合法的,并且text
是一个参数,那么这不能仅仅是以下内容吗?
(defun print-test (fn text)
(funcall fn text))
当然,这有点不同。在这里,如果您想要与(princ 'hi)
具有相同的效果,则只需传递符号princ
和hi
:
(print-test 'princ 'hi)