我正在处理这个程序,该程序应该返回来自2个给定列表的对列表。所以例如(对'(1 2 3)'(abc))应该返回'((1.a)(2.b)(3.c))。
到目前为止,这是我的逻辑。我将获取每个列表的第一个元素,并以cdr作为新参数再次递归调用该过程。我的结果是返回如下列表:(1 a 2 b 3 c)
我的逻辑错在哪里?我知道某处有一个列表缺失,但我不是Scheme的专家。
有什么建议吗?
(define pairs
(lambda (x y)
(if (or (null? x) (null? y))
'()
(cons (car x)
(cons (car y)
(pairs (cdr x)(cdr y)))))))
(pairs '(1 2 3) '(a b c))
答案 0 :(得分:3)
请注意,您通过评估(1 . 3)
生成一个打印为(cons 1 3)
的值。但是,在您的程序中,您正在执行(cons 1 (cons 3 ...))
,它将1和3添加到以下列表中。
换句话说:而不是(cons (car x) (cons (car y) (pairs ...))
使用(cons (cons (car x) (car y) (pairs ...))
。
答案 1 :(得分:1)
您正在寻找的结果应如下所示:
((1 a) (2 b) (3 c))
实际上这种结构与此类似:
(cons
(cons 1 a)
(cons
(cons 2 b)
(cons
(cons 3 c)
'()
)
)
)
所以你要找的是将对添加到列表中而不是像你那样将所有项添加到列表中。只是你的结果如下:
(1 (2 (pairs ...)))
您的代码应如下所示:
(define pairs
(lambda (x y)
(if (or (null? x) (null? y))
'()
(cons
(cons (car x) (car y))
(pairs (cdr x) (cdr y))))))
此代码可能有用,但并不完美。我们可以让代码传递我们创建的列表作为第三个参数,使函数tail递归。
你会有这样的事情:
(define pairs
(lambda (x y)
(let next ((x x) (y y) (lst '()))
(if (or (null? x) (null? y))
(reverse lst)
(next (cdr x)
(cdr y)
(cons
(cons (car x) (car y))
lst))))))
正如您所看到的,由于我们在列表的开头添加了下一个元素,因此我们必须在结尾处反转lst
。这里的区别在于,每次调用next
时,都不需要将x和y的每个状态保留在内存中。当命名的let将返回时,没有必要将所有值弹回到它调用的位置。它只会返回反转列表。
也就是说,我们可以简单地返回reverse
并使用lst
而不是使用(append lst (cons (car x) (car y)))
,这会将该对添加到列表的末尾...因为列表是链接列表。 ..为了在列表的末尾附加一些东西,scheme必须遍历所有列表项...这对于大列表而言并不好。所以解决方案是添加所有内容,最后根据需要重新排序列表。反向操作只会发生一次。
答案 2 :(得分:1)
使用taylor_sin
可以简化它:
map
测试:
(define (pairs x y)
(map (λ (i j) (list i j)) x y))
输出:
(pairs '(1 2 3) '(a b c))