Lisp 合并和提取列表

Lisp 合并和提取列表,lisp,scheme,Lisp,Scheme,我正在编写一个合并两个列表的函数。如果列表中的一个项目是列表,我也需要提取它 list1:'(1 (2 3 4) 5 6)) list2: '(7 (8 9) 10 (11)) output: (1 2 3 4 5 6 7 8 9 10 11) 我试图用我的代码来解决它,但代码不起作用。有什么问题 (define (merge lis1 lis2) (define (combine lis fine) (cond ((null? lis)

我正在编写一个合并两个列表的函数。如果列表中的一个项目是列表,我也需要提取它

list1:'(1 (2 3 4) 5 6)) 

list2: '(7 (8 9) 10 (11))

output: (1 2 3 4 5 6 7 8 9 10 11)
我试图用我的代码来解决它,但代码不起作用。有什么问题

(define (merge lis1 lis2)
    (define (combine lis fine)
        (cond
            ((null? lis) lis)
            ((list? lis) (combine (car lis) fine) (combine (cdr lis) fine))
            (else  (cons lis fine))))

        (cond
            (combine (cons lis2 lis1) '())))

最简单的方法是简单地使用库函数
flatten

(define (merge lis1 lis2)
  (flatten (cons lis1 lis2)))
展平
获取一个可以包含列表的列表(而列表又可以包含更多列表,…),并将结果展平为非列表列表列表,这似乎是您的联合收割机函数所要做的

(展平’(12(3(4 5)6))
返回
(1 2 3 4 5 6)

如果这个库函数是禁止使用的,那么您的代码实际上是非常接近正确的

第一个问题出现在
((列表?lis)(联合收割机(汽车lis)精细)(联合收割机(cdr lis)精细))行上
fine
从未更改,因此代码计算
(组合(汽车lis)fine)
,然后返回
(组合(cdr lis)fine)
,其中第二个表达式中的
fine
fine
的原始值。这一行与
((list?lis)(combine(cdr lis)fine))相同,这显然不是我们想要的。相反,我们必须在第二个表达式中使用第一个表达式
((list?lis)(combine(cdr lis)(combine(car lis)fine))

第二个问题是,在combine中,当
lis
为空时,我们需要返回
fine
,而不是
lis

下一个问题是,此代码遍历列表,获取
lis
的第一个元素并将其放在
fine
的前面,然后传递新创建的列表并将其用于函数的下一次迭代,其中它在
lis
中获取第二个值并将其粘贴在新
fine
的前面,在
lis的第一个值前面
。按照
fine
的返回值被反转的顺序--
(merge'(1 2(3))(4(5 6))
将返回
(6 5 4 3 2 1)
。我们有两种选择:我们可以在
merge
主体中的
combine
返回时调用reverse,或者我们可以反转上面更改的行,使其
((list?lis)(combine(car lis)(combine(cdr lis)fine))
。这意味着在添加当前元素之前,我们将把列表的其余部分添加到
fine
,这正是我们想要的

另一个问题是,我们需要将
lis1
转换为
lis2
,而不是相反

最后一个问题是,
merge
主体中的
cond
是不必要的——我们可以删除它

作为旁注,通常认为不给右括号换行并将
define
cond
的正文缩进两个空格更为简洁

经过所有这些更改,最终代码为:

(define (merge lis1 lis2)
  (define (combine lis fine)
    (cond
      ((null? lis) fine)
      ((list? lis) (combine (car lis)
                            (combine (cdr lis) fine)))
      (else  (cons lis fine))))

  (combine (cons lis1 lis2) '()))