(apply #'somefunc args) 和 (somefunc args) 之间的区别
Difference between (apply #'somefunc args) and (somefunc args)
在阅读 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 ...)
中做。
当您调用 (f args)
时,您调用 f
时带有一个参数。
使用 (apply #'f args)
,您可以使用 args
列表包含的参数调用 f
。所以如果args
是(1 2)
,那么(apply #'f args)
就等价于(f 1 2)
.
见APPLY
。
我们来看看mkstr
的定义:
CL-USER> (defun mkstr (&rest args)
(with-output-to-string (s)
(dolist (a args) (princ a s))))
MKSTR
它是一个函数,它接受可变数量的任何类型的参数,将它们打包在一个列表中,并将该列表分配给形式参数 args
(由于 &rest
规范参数)。然后,该函数使用 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), 这样列表的所有元素都被连接在一起,然后转化为一个原子..
APPLY 的目的是调用带有计算参数列表的函数。
假设用户输入了一些参数,我们想要调用函数 WRITE
。 WRITE
需要很多可能的参数。第一个参数是要打印的对象,其余是关键字值选项:
WRITE
的可能关键字参数:
array base case circle escape gensym
length level lines miser-width pprint-dispatch
pretty radix readably right-margin stream
让我们使用 READ
将参数列表作为列表读取,并使用参数列表通过 APPLY
调用 WRITE
:
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
在阅读 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 ...)
中做。
当您调用 (f args)
时,您调用 f
时带有一个参数。
使用 (apply #'f args)
,您可以使用 args
列表包含的参数调用 f
。所以如果args
是(1 2)
,那么(apply #'f args)
就等价于(f 1 2)
.
见APPLY
。
我们来看看mkstr
的定义:
CL-USER> (defun mkstr (&rest args)
(with-output-to-string (s)
(dolist (a args) (princ a s))))
MKSTR
它是一个函数,它接受可变数量的任何类型的参数,将它们打包在一个列表中,并将该列表分配给形式参数 args
(由于 &rest
规范参数)。然后,该函数使用 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), 这样列表的所有元素都被连接在一起,然后转化为一个原子..
APPLY 的目的是调用带有计算参数列表的函数。
假设用户输入了一些参数,我们想要调用函数 WRITE
。 WRITE
需要很多可能的参数。第一个参数是要打印的对象,其余是关键字值选项:
WRITE
的可能关键字参数:
array base case circle escape gensym
length level lines miser-width pprint-dispatch
pretty radix readably right-margin stream
让我们使用 READ
将参数列表作为列表读取,并使用参数列表通过 APPLY
调用 WRITE
:
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