eval如何以这种方式处理函数

时间:2013-11-15 06:16:27

标签: lisp common-lisp

我正在尝试查看数据与代码替换在使用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机制如何动态生成代码。

1 个答案:

答案 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作为符号princtext作为列表 '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)具有相同的效果,则只需传递符号princhi

(print-test 'princ 'hi)