如何压扁嵌套系列?

时间:2013-07-24 05:19:40

标签: common-lisp

使用SERIES library from CLTL2 appendix A,我想要一个嵌套系列的平面系列。例如:

(map-fn t (lambda (x)
            (map-fn t (lambda (y)
                        (cons x y))
                    (scan '(1 2 3))))
        (scan '(4 5 6)))

=> #Z( #Z( (4 . 1) (4 . 2) (4 . 3) )
       #Z( (5 . 1) (5 . 2) (5 . 3) )
       #Z( (6 . 1) (6 . 2) (6 . 3) ) )

我想将这一系列系列制作成如下系列:

=> #Z( (4 . 1) (4 . 2) (4 . 3)
       (5 . 1) (5 . 2) (5 . 3)
       (6 . 1) (6 . 2) (6 . 3) )

如果我有一个合适的系列连接函数,那就太好了。虽然系列库具有CATENATE功能,但它的& rest参数只需要一些系列。我可以

(apply #'catenate list-of-series)

但是它接受系列的列表,而不是系列的系列。不幸的是,折叠系列没有任何功能,而有映射和过滤功能。生产宏在A.4上显示。 CLTL2中的Primitives部分对我不起作用,因为它似乎也没有展平嵌套循环。我无法在嵌套情况下使用NEXT-OUT宏。

1 个答案:

答案 0 :(得分:3)

(apply #'catenate
       (collect (map-fn t (lambda (x)
                            (map-fn t (lambda (y)
                                        (cons x y))
                                    (scan '(1 2 3))))
                        (scan '(4 5 6)))))

但这有点像作弊。要正确地系列化:

(producing (prod) ((zz (generator (map-fn t (lambda (x)
                                              (map-fn t (lambda (y)
                                                          (cons x y))
                                                      (scan '(1 2 3))))
                                          (scan '(4 5 6)))))
                   cur)
           (loop
              (tagbody
               redo
                 (if (null cur)
                     (setq cur (generator (next-in zz (terminate-producing)))))
                 (next-out prod (next-in cur (progn 
                                               (setq cur nil)
                                               (go redo)))))))

=> #Z((4 . 1) (4 . 2) (4 . 3)
      (5 . 1) (5 . 2) (5 . 3)
      (6 . 1) (6 . 2) (6 . 3))