在 Lisp 的 mapcon 上应用附加
Applying append on mapcon in Lisp
The Lisp function G
is defined by:
(defun g (l)
(mapcon #'list l))
What is the result of evaluating the form (apply #'append (mapcon #'g '(1 2)))
?
Justify the answer.
我看到 mapcon
与 nconc
和 cdr
一起使用,但最终答案将是 (1 2 2 2)
,我不知道如何正确解释它。请帮忙。
首先,让我们调用:
(mapcon (lambda (list) (print list) nil) '(1 2))
因为匿名函数returns一直为NIL,结果列表为NIL;调用打印如下:
(1 2)
(2)
因此在您的示例中,当您调用 (mapcon #'g '(1 2))
时,g
将首先用 (1 2)
调用,然后用 (2)
调用。函数 g
returns 一个列表,mapcon
连接它们。
可以通过显式计算每个部分在 REPL 中复制发生的事情:
USER> (mapcon #'list '(1 2))
((1 2) (2))
USER> (mapcon #'list '(2))
((2))
USER> (nconc ** *)
((1 2) (2) (2))
最后,(apply #'append list-of-lists)
使用参数列表调用 append
。
append
的签名是:
append &rest lists => result
也就是说,如果l1
、l2
和l3
是列表,则包含它们所有元素的列表是:
(append l1 l2 l3)
此处 append
的参数存储在列表中,因此将任意参数列表传递给函数的方法是使用 apply
。所以这意味着 (apply #'append lists)
连接列表中的所有列表,这就是为什么在你的情况下结果是 (1 2 2 2)
.
请注意,当参数的数量是任意的(可能很大)时,不建议使用 apply
,因为 apply
受到 CALL-ARGUMENTS-LIMIT
的限制。另一种可能的方法是:
(loop for list in lists append list)
这里要理解的主要是
(mapcon #'f xs) = (apply #'nconc (maplist #'f xs))
= (loop for ys on xs nconc (f ys))
所以
(g xs) =
(mapcon #'list xs) = (apply #'nconc (maplist #'list xs))
= (loop for ys on xs nconc (list ys))
= (loop for ys on xs append (list ys))
= (loop for ys on xs collect ys )
;; = (maplist #'identity xs)
这只是 #'cdr
对参数列表的迭代应用,收集其非空后缀:
[4]> (loop for ys on '(1 2) collect ys) ; (g '(1 2))
((1 2) (2))
[5]> (loop for ys on '( 2) collect ys) ; (g '( 2))
( (2))
因此我们有
(mapcon #'g '(1 2))
=
(loop for ys on '(1 2) nconc (g ys))
=
(loop for ys in '((1 2) (2)) nconc (g ys)) ; ----- 'in' NB
=
(nconc (g '(1 2)) (g '(2)))
=
(append '((1 2) (2)) '((2)))
=
'( (1 2) (2) (2) )
因此
(apply #'append (mapcon #'g '(1 2)))
=
(apply #'append (nconc (g '(1 2)) (g '(2))))
=
(apply #'append (append '((1 2) (2)) '((2))))
=
(apply #'append '( (1 2) (2) (2) ))
=
( append '(1 2)'(2) '(2) )
=
'( 1 2 2 2 )
The Lisp function
G
is defined by:(defun g (l) (mapcon #'list l))
What is the result of evaluating the form
(apply #'append (mapcon #'g '(1 2)))
?
Justify the answer.
我看到 mapcon
与 nconc
和 cdr
一起使用,但最终答案将是 (1 2 2 2)
,我不知道如何正确解释它。请帮忙。
首先,让我们调用:
(mapcon (lambda (list) (print list) nil) '(1 2))
因为匿名函数returns一直为NIL,结果列表为NIL;调用打印如下:
(1 2)
(2)
因此在您的示例中,当您调用 (mapcon #'g '(1 2))
时,g
将首先用 (1 2)
调用,然后用 (2)
调用。函数 g
returns 一个列表,mapcon
连接它们。
可以通过显式计算每个部分在 REPL 中复制发生的事情:
USER> (mapcon #'list '(1 2))
((1 2) (2))
USER> (mapcon #'list '(2))
((2))
USER> (nconc ** *)
((1 2) (2) (2))
最后,(apply #'append list-of-lists)
使用参数列表调用 append
。
append
的签名是:
append &rest lists => result
也就是说,如果l1
、l2
和l3
是列表,则包含它们所有元素的列表是:
(append l1 l2 l3)
此处 append
的参数存储在列表中,因此将任意参数列表传递给函数的方法是使用 apply
。所以这意味着 (apply #'append lists)
连接列表中的所有列表,这就是为什么在你的情况下结果是 (1 2 2 2)
.
请注意,当参数的数量是任意的(可能很大)时,不建议使用 apply
,因为 apply
受到 CALL-ARGUMENTS-LIMIT
的限制。另一种可能的方法是:
(loop for list in lists append list)
这里要理解的主要是
(mapcon #'f xs) = (apply #'nconc (maplist #'f xs))
= (loop for ys on xs nconc (f ys))
所以
(g xs) =
(mapcon #'list xs) = (apply #'nconc (maplist #'list xs))
= (loop for ys on xs nconc (list ys))
= (loop for ys on xs append (list ys))
= (loop for ys on xs collect ys )
;; = (maplist #'identity xs)
这只是 #'cdr
对参数列表的迭代应用,收集其非空后缀:
[4]> (loop for ys on '(1 2) collect ys) ; (g '(1 2))
((1 2) (2))
[5]> (loop for ys on '( 2) collect ys) ; (g '( 2))
( (2))
因此我们有
(mapcon #'g '(1 2))
=
(loop for ys on '(1 2) nconc (g ys))
=
(loop for ys in '((1 2) (2)) nconc (g ys)) ; ----- 'in' NB
=
(nconc (g '(1 2)) (g '(2)))
=
(append '((1 2) (2)) '((2)))
=
'( (1 2) (2) (2) )
因此
(apply #'append (mapcon #'g '(1 2)))
=
(apply #'append (nconc (g '(1 2)) (g '(2))))
=
(apply #'append (append '((1 2) (2)) '((2))))
=
(apply #'append '( (1 2) (2) (2) ))
=
( append '(1 2)'(2) '(2) )
=
'( 1 2 2 2 )