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