在阅读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 ...)
。
答案 0 :(得分:4)
当您致电(f args)
时,请使用一个参数致电f
。
使用(apply #'f args)
,您可以使用f
列表中包含的参数调用args
。因此,如果args
为(1 2)
,则(apply #'f args)
相当于(f 1 2)
。
请参阅APPLY
。
答案 1 :(得分:4)
APPLY的目的是用计算参数列表调用函数。
想象一下,用户输入了一些参数,我们想要调用函数WRITE
。 WRITE
需要很多可能的论据。第一个参数是打印其余部分的对象是关键字值选项:
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)"
类似地,函数symb
和symb1
采用可变数量的参数,args
将包含由它们形成的列表。因此,symb1
使用单个参数调用mkstr
,传递给symb1
的参数列表,以便mkstr
创建一个唯一的字符串列表,最后列表被实习以在原子中转换它。相反,在symb
中,函数mkstr
将应用于列表中提取的所有参数,因为使用了apply
(请参阅specification ),以便列表中的所有元素连接在一起,然后转换为原子..