列表上的递归在追加时返回空列表

时间:2014-10-26 14:07:17

标签: list scheme

我在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)'()'())

它总是返回空列表()

我做错了什么?

2 个答案:

答案 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,而不是嵌套ifbegin s
  • 使用positive?测试数字是否大于零
  • 将结果作为参数传递,如上所述,只需附加它们(或托付它们,或其他任何内容)就不会就地修改列表
  • 尽可能使用cons,而不是append - 它便宜得多,因为它会在列表的头部添加元素,而append会遍历整个列表并创建一个新列表,除了它的最后一个参数也应该是一个列表,用于构建一个正确的列表

关于最后一点,如果您绝对必须保留输入列表中的原始订单,那么最好使用cons然后reverse最后的输出列表 - 再一次,避免append。例如,这是示例输入的输出:

(joinLists '(4 5 -5 -4) '() '())
=> '((5 4) (-4 -5))