简体   繁体   中英

recursion over lists return empty list while appending

I am writing a program in Scheme that receives one list with numbers and two empty lists. I would like that the positive numbers are joined to one list, while the negative numbers are put in another list. At the end I would like to return the join of both lists. I am using for this purpose append like this:

(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))))

but when I run it with some data like:

(joinLists '(4 5 -5 -4) '() '())

it always returns the empty list ()

what am I doing wrong?

append does not change the value of the list, it produces a new list with the given item appended. Since you don't actually use the value produced by append , your use of append has no effect at all. As a general rule of thumb using begin only makes sense when the functions you're calling in it have side-effects, which append does not.

What you should do is pass the result of the append as an argument to the recursive call to joinLists .

The way you're using append is wrong. Sure, we can write this:

(append list1 (list (car listInic))) ; second argument should be a list

… but the list1 parameter is not being modified in-place, instead a new list is created - and given that you didn't assign it or pass it around as aa parameter, then the new list is lost - that's why you're always getting an empty list as a result, the list parameters were never modified. We have to do something like this:

(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)))))

Some points to consider:

  • It's better to use cond when we have multiple conditions, instead of nesting if s and begin s
  • Use positive? to test if a number is greater than zero
  • Pass the results around as parameters, as mentioned above, simply appending them (or consign them, or whatever) won't modify lists in-place
  • Use cons whenever possible, instead of append - it's much cheaper, because it adds elements at the head of the list, whereas append traverses the whole list and creates a new list, and besides its last argument should also be a list, for building a proper list

Regarding the last point, if you absolutely have to preserve the original order from the input list, even so it would be better to use cons and then reverse the output lists at the end - one again, avoiding append . For instance, here's the output for the sample input:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM