Lisp 使用mapcan冻结创建列表的重复?
我有两个列表:Lisp 使用mapcan冻结创建列表的重复?,lisp,common-lisp,Lisp,Common Lisp,我有两个列表:(1233)和(ab),我需要创建这样的(12312313)。结果是第一个列表的连接次数与第二个列表中的元素数量相同。我应该使用一些函数(maplist/mapcar/mapcon等)。这正是我需要的,尽管我需要将第一个列表作为参数传递: (mapcan #'(lambda (x) (list 1 2 3)) (list 'a 'b)) ;=> (1 2 3 1 2 3) 但是,当我试图将其抽象为函数时,Allegro冻结了: (defun foo (a b) (map
(1233)
和(ab)
,我需要创建这样的(12312313)
。结果是第一个列表的连接次数与第二个列表中的元素数量相同。我应该使用一些函数(maplist
/mapcar
/mapcon
等)。这正是我需要的,尽管我需要将第一个列表作为参数传递:
(mapcan #'(lambda (x) (list 1 2 3)) (list 'a 'b))
;=> (1 2 3 1 2 3)
但是,当我试图将其抽象为函数时,Allegro冻结了:
(defun foo (a b)
(mapcan #'(lambda (x) a) b))
(foo (list 1 2 3) (list 'a 'b))
; <freeze>
(defun foo(a-b)
(mapcan#’(lambda(x)a)b)
(foo(清单1、2、3)(清单a、b))
;
为什么这个定义不起作用?你可以
(defun f (lst1 lst2)
(reduce #'append (mapcar (lambda (e) lst1) lst2)))
然后
你可以
(defun f (lst1 lst2)
(reduce #'append (mapcar (lambda (e) lst1) lst2)))
然后
已经有了一个公认的答案,但我认为应该对原始代码中的错误进行更多的解释
mapcan
对列表的每个元素应用一个函数,以生成一组以破坏性方式连接在一起的列表。如果将列表与其自身进行破坏性连接,则会得到一个循环列表。例如:
(let ((x (list 1 2 3)))
(nconc x x))
;=> (1 2 3 1 2 3 1 2 3 ...)
现在,如果有多个连接,则无法完成,因为要将某些内容连接到列表的末尾,需要走到列表的末尾。所以
(let ((x (list 1 2 3)))
(nconc (nconc x x) x))
; ----------- (a)
; --------------------- (b)
(a) 终止,并返回列表(1 2 3 1 2 3 1 2 3…
),但(b)无法终止,因为我们无法到达(1 2 3 1 2 3…
的末尾,以便在末尾添加内容
现在剩下的问题是为什么
(defun foo (a b)
(mapcan #'(lambda (x) a) b))
(foo (list 1 2 3) '(a b))
导致冻结。由于(a b)
中只有两个元素,这相当于:
(let ((x (list 1 2 3)))
(nconc x x))
它应该终止并返回一个无限列表(123123…
)。事实上,确实如此。问题是在REPL中打印该列表将挂起。例如,在SBCL中:
CL-USER> (let ((x (list 1 2 3)))
(nconc x x))
; <I manually stopped this, because it hung.
CL-USER> (let ((x (list 1 2 3)))
(nconc x x) ; terminates
nil) ; return nil, which is easy to print
NIL
调整代码以删除有问题行为的最简单方法(即最少的更改次数)是在lambda函数中使用copy list
:
(defun foo (a b)
(mapcan #'(lambda (x)
(copy-list a))
b))
这也比
(reduce'append(mapcar…:from end t)
解决方案有一个优势,因为它不一定要分配一个中间结果列表。已经有了一个公认的答案,但我认为应该对原始代码中的错误进行更多的解释mapcan
对列表的每个元素应用一个函数,以生成一组以破坏性方式连接在一起的列表。如果将列表与其自身进行破坏性连接,则会得到一个循环列表。例如:
(let ((x (list 1 2 3)))
(nconc x x))
;=> (1 2 3 1 2 3 1 2 3 ...)
现在,如果有多个连接,则无法完成,因为要将某些内容连接到列表的末尾,需要走到列表的末尾。所以
(let ((x (list 1 2 3)))
(nconc (nconc x x) x))
; ----------- (a)
; --------------------- (b)
(a) 终止,并返回列表(1 2 3 1 2 3 1 2 3…
),但(b)无法终止,因为我们无法到达(1 2 3 1 2 3…
的末尾,以便在末尾添加内容
现在剩下的问题是为什么
(defun foo (a b)
(mapcan #'(lambda (x) a) b))
(foo (list 1 2 3) '(a b))
导致冻结。由于(a b)
中只有两个元素,这相当于:
(let ((x (list 1 2 3)))
(nconc x x))
它应该终止并返回一个无限列表(123123…
)。事实上,确实如此。问题是在REPL中打印该列表将挂起。例如,在SBCL中:
CL-USER> (let ((x (list 1 2 3)))
(nconc x x))
; <I manually stopped this, because it hung.
CL-USER> (let ((x (list 1 2 3)))
(nconc x x) ; terminates
nil) ; return nil, which is easy to print
NIL
调整代码以删除有问题行为的最简单方法(即最少的更改次数)是在lambda函数中使用copy list
:
(defun foo (a b)
(mapcan #'(lambda (x)
(copy-list a))
b))
与
(reduce'append(mapcar…:from end t)
解决方案相比,这也有一个优势,因为它不一定要分配一个中间结果列表。经验法则是确保提供给mapcan
(和破坏性朋友)的函数创建列表,否则将创建一个循环。这同样适用于提供给其他破坏性函数的参数。通常情况下,如果函数已经生成了它们,则最好只进行线性更新
这将有助于:
(defun foo (a b)
(mapcan #'(lambda (x) (copy-list a)) b))
以下是一些备选方案:
(defun foo (a b)
;; NB! apply sets restrictions on the length of b. Stack might blow
(apply #'append (mapcar #'(lambda (x) a) b))
(defun foo (a b)
;; uses loop macro
(loop for i in b
append a))
我真的不明白为什么b不能是数字?你真的把它当作教堂的号码,所以我想我应该这样做:
(defun x (list multiplier)
;; uses loop
(loop for i from 1 to multiplier
append list))
(x '(a b c) 0) ; ==> nil
(x '(a b c) 1) ; ==> (a b c)
(x '(a b c) 2) ; ==> (a b c a b c)
;; you can still do the same:
(x '(1 2 3) (length '(a b))) ; ==> (1 2 3 1 2 3)
经验法则是确保提供给
mapcan
(和破坏性朋友)的函数创建列表,否则将创建循环。这同样适用于提供给其他破坏性函数的参数。通常情况下,如果函数已经生成了它们,则最好只进行线性更新
这将有助于:
(defun foo (a b)
(mapcan #'(lambda (x) (copy-list a)) b))
以下是一些备选方案:
(defun foo (a b)
;; NB! apply sets restrictions on the length of b. Stack might blow
(apply #'append (mapcar #'(lambda (x) a) b))
(defun foo (a b)
;; uses loop macro
(loop for i in b
append a))
我真的不明白为什么b不能是数字?你真的把它当作教堂的号码,所以我想我应该这样做:
(defun x (list multiplier)
;; uses loop
(loop for i from 1 to multiplier
append list))
(x '(a b c) 0) ; ==> nil
(x '(a b c) 1) ; ==> (a b c)
(x '(a b c) 2) ; ==> (a b c a b c)
;; you can still do the same:
(x '(1 2 3) (length '(a b))) ; ==> (1 2 3 1 2 3)
那么,规格是什么?“给定列表
a
和b
,构造一个新的列表c
,这样它是a
与自身的串联;c
中a
元素的重复次数是b
的长度。”。是吗?那么,规格是什么?“给定列表a
和b
,构造一个新的列表c
,这样它是a
与自身的串联;c
中a
元素的重复次数是b
的长度。”。是吗?不过你应该小心使用(reduce'append…
,因为它会制作大量的列表副本。例如,见。(你实际上也参与了这个线程。)因此,这应该是(reduce'append…:从t端开始)
。但是你应该小心(reduce'append…
,因为它会生成大量列表的副本。例如,见。(你实际上也参与了这个线程。)因此,这应该是(reduce'append…:从t端开始)
。我运行了两个函数:(defun foo1(ab)(reduce#'append(mapcar(lambda)b):从t端开始)
和(defun foo2(ab)(mapcan#'(lambda(x)(copy list a))与(time(foo1'(a b c d e f g h i j k l m n o p r s t u v w x