0

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.

user16655
  • 1,901
  • 6
  • 36
  • 60

2 Answers2

1

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)
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
0

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
Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • Thank you very much. I have to read about some of the things you are using, but I think I (almost) understand how it works. What would I do if I wouldn't want it to return a value? Is it possible? So in the (null? lst) case, I wouldn't want a return value. – user16655 Mar 26 '15 at 22:47
  • @user16655 It's not like you see the values unless you use them so does it really matter if every procedure returns a value or not? (When running as a application all Scheme implementation will never print anything except when errors occur or you use `display/print`) Some of the special forms and procedures are described to return undefined values and many Scheme implementations have value representing that and their REPL will simply not print it. eg. `(if #f #f)` in r6rs would produce one. You can also evaluate `(values)` but that means you restrict where you can apply your procedure. – Sylwester Mar 26 '15 at 23:15