(应用#' somefunc args)和(somefunc args)

时间:2016-12-12 21:02:13

标签: common-lisp on-lisp

在阅读Paul Graham的On Lisp时,我在第4章,效用函数中找到了以下function

(defun symb (&rest args)
  (values (intern (apply #'mkstr args)))) ;; mkstr function is "applied"
;; which evaluates like in the following example:
> (symb nil T :a)
NILTA

我想了解与以下功能有什么不同,略有不同:

(defun symb1 (&rest args)
  (values (intern (mkstr args)))) ;; directly calling mkstr
;; which evaluates like in the following example:
> (symb1 nil T :a)
|(NIL T A)|

在第二个版本中,使用mkstr参数直接评估args,但我不明白为什么我们需要在原始版本中执行(apply #'mkstr ...)

3 个答案:

答案 0 :(得分:4)

当您致电(f args)时,请使用一个参数致电f

使用(apply #'f args),您可以使用f列表中包含的参数调用args。因此,如果args(1 2),则(apply #'f args)相当于(f 1 2)

请参阅APPLY

答案 1 :(得分:4)

APPLY的目的是用计算参数列表调用函数。

想象一下,用户输入了一些参数,我们想要调用函数WRITEWRITE需要很多可能的论据。第一个参数是打印其余部分的对象是关键字值选项:

WRITE的可能关键字参数:

array base case circle escape gensym
length level lines miser-width pprint-dispatch
pretty radix readably right-margin stream

让我们使用READ将参数列表作为列表阅读,并使用参数列表通过WRITE调用APPLY

CL-USER 30 > (loop for input = (read)
                   while input
                   do
                   (format t "~%# ")
                   (apply #'write input)
                   (format t "~%~%"))
((1 5 10 30 55 26 12 17))
# (1 5 10 30 55 26 12 17)

((1 5 10 30 55 26 12 17) :base 16)
# (1 5 A 1E 37 1A C 11)

((1 5 10 30 55 26 12 17) :base 12)
# (1 5 A 26 47 22 10 15)

((1 5 10 30 55 26 12 17) :length 5)
# (1 5 10 30 55 ...)

((1 5 10 30 55 26 12 17) :base 16 :length 5)
# (1 5 A 1E 37 ...)

实现类似目标的另一种方法是使用EVAL。

CL-USER 35 > (let ((f #'+)
                   (args '(20 22)))
               (eql (eval (list* 'funcall f args))
                    (apply f args)))
T

答案 2 :(得分:2)

让我们看一下mkstr

的定义
CL-USER> (defun mkstr (&rest args)
           (with-output-to-string (s)
             (dolist (a args) (princ a s))))
MKSTR

它是一个函数,它接受任意类型的可变数量的参数,将它们打包在列表中,并将此列表分配给形式参数args(由于&rest的{​​{1}}规范参数)。然后,该函数使用printc打印此列表的所有元素,生成一个字符串,该字符串是连接所有打印的表示形式的结果(没有插入空格)。所以,例如:

CL-USER> (mkstr '(a b c))
"(A B C)"
CL-USER> (mkstr 3 'A '(A b 4))
"3A(A B 4)"

类似地,函数symbsymb1采用可变数量的参数,args将包含由它们形成的列表。因此,symb1使用单个参数调用mkstr,传递给symb1的参数列表,以便mkstr创建一个唯一的字符串列表,最后列表被实习以在原子中转换它。相反,在symb中,函数mkstr将应用于列表中提取的所有参数,因为使用了apply(请参阅specification ),以便列表中的所有元素连接在一起,然后转换为原子..