我在Scheme中编写一个程序,它接收一个包含数字和两个空列表的列表。我希望将正数加到一个列表中,而将负数加到另一个列表中。最后,我想返回两个列表的连接。我为此目的使用如下:
(define (joinLists listInic list1 list2)
(if (empty? listInic)
(append list1 list2)
(begin
(if (> (car listInic) 0)
(append list1 (car listInic))
(append list2 (car listInic))
)
(joinLists (cdr listInic) list1 list2))))
但是当我用一些数据运行它时:
(joinLists'(4 5 -5 -4)'()'())
它总是返回空列表()
我做错了什么?
答案 0 :(得分:2)
append
不会更改列表的值,它会生成一个附加给定项目的新列表。由于您实际上并未使用append
生成的值,因此您对append
的使用完全没有效果。作为使用begin
的一般经验法则,只有当您在其中调用的函数具有副作用时才有意义,而append
则没有。
您应该做的是将append
的结果作为参数传递给递归调用joinLists
。
答案 1 :(得分:2)
您使用append
的方式是错误的。当然,我们可以这样写:
(append list1 (list (car listInic))) ; second argument should be a list
...但是list1
参数是而不是被就地修改,而是创建了一个新列表 - 并且假设您没有将其分配或作为参数传递给它,然后新列表丢失 - 这就是为什么你总是得到一个空列表的原因,列表参数从未被修改过。我们必须做这样的事情:
(define (joinLists listInic list1 list2)
(cond ((empty? listInic)
(list list1 list2))
((positive? (car listInic))
(joinLists (cdr listInic) (cons (car listInic) list1) list2))
(else
(joinLists (cdr listInic) list1 (cons (car listInic) list2)))))
需要考虑的一些要点:
cond
,而不是嵌套if
和begin
s positive?
测试数字是否大于零cons
,而不是append
- 它便宜得多,因为它会在列表的头部添加元素,而append
会遍历整个列表并创建一个新列表,除了它的最后一个参数也应该是一个列表,用于构建一个正确的列表关于最后一点,如果您绝对必须保留输入列表中的原始订单,那么最好使用cons
然后reverse
最后的输出列表 - 再一次,避免append
。例如,这是示例输入的输出:
(joinLists '(4 5 -5 -4) '() '())
=> '((5 4) (-4 -5))