Loops 如何在Lisp中使用嵌套循环生成对

Loops 如何在Lisp中使用嵌套循环生成对,loops,while-loop,lisp,Loops,While Loop,Lisp,我正在尝试用Lisp制作一个pairs函数。pairs函数获取两个输入,然后彼此配对并生成一个列表。这是我的密码: (defun npair (s1 s2) (let ((result '())) (cond ((null s1) s2) ((null s2) s1) (t (loop (when (null s1) (return result)) (while (not (null

我正在尝试用Lisp制作一个pairs函数。pairs函数获取两个输入,然后彼此配对并生成一个列表。这是我的密码:

(defun npair (s1 s2)
  (let ((result '()))
    (cond ((null s1) s2)
          ((null s2) s1)
          (t (loop
               (when (null s1) (return result))
               (while (not (null s2))
                 (setq result (cons (list (car s1) (car s2)) result))
                 (setq s2 (cdr s2)))
               (setq s1 (cdr s1)))))))
此函数应该像
(npair'(abc)'(12))
->
((a1)(a2)(b1)(b2)(c1)(c2))

但我的结果只有
((a1)(a2))

请帮忙

如果您想在外部循环中累积来自内部循环的值,您最好简单地累积这些值,而不是尝试通过变异变量来完成:

(loop for e1 in p1
   append (loop for e2 in p2
             collect (list e1 e2)))
您的格式设置也有偏差,自定义设置是不在新行上放置终止括号

使用上面的循环构造,您的整个函数将是:

(defun npair (p1 p2)
   (loop for e1 in p1
      append (loop for e2 in p2
                collect (list e1 e2))))

漂亮、简单、可读性强。

从外观上看,您希望得到的结果称为笛卡尔积

我在Scheme编程语言中使用的实现如下所示:

(define (product . args)                                                             
   (if (null? args)                                                                   
       (list '())                                                                     
       (apply append                                                                  
              (map (lambda (rest)                                                    
                    (map (lambda (first)                                             
                            (cons first rest))                                       
                          (car args)))                                               
                  (apply product (cdr args))))))
例如,以下是使用Chez方案的输出:

> (product '(a b c) '(1 2))
 ((a 1) (b 1) (c 1) (a 2) (b 2) (c 2)) 

虽然其他人向您展示了比您的实现更好的方法来实现您想要的结果,但以下是您的实现不起作用的原因:您将
s2
的值更改为
null
,同时将
s1
的第一个元素与
s2
的元素组合在一起,在处理
s1
的其余元素之前,切勿恢复
s2
的原始值。(这是一个很好的理由,为什么您应该循环输入值而不首先改变它们。)

以下是您的实现的一个版本,它实际上可以工作,因为它不会改变输入:

(defun npair (s1 s2)
  (let ((result '()))
    (cond ((null s1) s2)
          ((null s2) s1)
          (t (loop for e1 in s1
                do (loop for e2 in s2
                      do (push (list e1 e2) result)))
             (nreverse result)))))

未知时,您的代码无法运行。您的
null
案例条件表示这不是正确的笛卡尔积。如果任一列表为空,则结果必须为空:因为非空列表的每个元素与空列表的每个元素的组合为空。当然,我们可以定义一个我们喜欢的函数;如果它输出免费的特殊情况,它就不可能有有用的价值。