简体   繁体   中英

Recursive method in Scheme

I have a (in theory) simple method in Scheme, that has to use recursion. The problem is that I can't seem to figure out the recursion part... I have a procedure that takes a 'pointer' and arbitrary many arguments, and I need to pass the arguments one by one to another method. Here is what I got so far:

(define (push-elements ptr . args)
    (define (push-all ptr list)
        (if (null? list)
            '()
            (ptr 'push-elements (car list))))
     (push-all ptr list))

I know there is no recursion here, but I can't understand where to put it/how to do it. The thought is clear, inside 'push-all' I need to call:

(push-all ptr (cdr list))

If anyone could help me (and I would be very grateful for an explanation on how to go about making such a recursive method), that would be great.

It's helpful to consider the base case and each incremental case. If you try to push-all onto a stack but have no items, what should the result be? Just the stack. If you try to push-all onto a stack and you have multiple items, what's the result? Well, first you'd push the first of the items onto the stack, giving you a new stack. Then you can push-all the rest of the items onto that stack:

(define (push-all stack items)
  (if (null? items)
      stack
      (let ((new-stack (cons (car items) stack))
            (remaining-items (cdr items)))
        (push-all new-stack remaining-items))))

(display (push-all '(1 2) '(a b c)))
;=> (c b a 1 2)

Now, your original version was variadic. That is, it accepts any number (well, greater than zero) of arguments because of the dotted arglist. That's fine, but it does mean that you'll need to use apply in setting up the recursive call:

(define (push-all stack . items)
  (if (null? items)
      stack
      (let ((new-stack (cons (car items) stack))
            (remaining-items (cdr items)))
        (apply push-all new-stack remaining-items))))

(display (push-all '(1 2) 'a 'b 'c))
;=> (c b a 1 2)

Basically you are implementing a variant of for-each , which is like map just for the side effects:

(define (for-each procedure lst)
  (let loop ((lst lst))
    (if (null? lst)        
        'undefined-value
        (begin
          (procedure (car lst))
          (loop (cdr lst))))))

(for-each display (list 1 2 3 4)) ; prints 1234

But you wanted to be able to specify the values as arguments so you need to change lst to be a rest argument:

(define (for-each-arg procedure . lst) ; changed to dotted list / rest here
  (let loop ((lst lst))
    (if (null? lst)        
        'undefined-value
        (begin
          (procedure (car lst))
          (loop (cdr lst))))))

(for-each-arg display 1 2 3 4) ; prints 1234

If you want a more functional approach you are indeed making either a map or a fold. Perhaps a fold-left would be preferred:

(define (fold-args join init . lst)
  (let loop ((acc init) (lst lst))
    (if (null? lst)
        acc
        (loop (join (car lst) acc) (cdr lst)))))

(fold-args cons '() 1 2 3 4) ; ==> (4 3 2 1)

You can actually implement for-each-arg with this:

(define (for-each-arg procedure . lst)
  (apply fold-args 
         (lambda (x acc) 
           (procedure x) 
           'undefined) 
         'undefined 
         lst))

(for-each-arg display 1 2 3 4) ; => undefined-value; prints 1234

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