3

I've asked a few questions here about Scheme/SICP, and quite frequently the answers involve using the apply procedure, which I haven't seen in SICP, and in the book's Index, it only lists it one time, and it turns out to be a footnote.

Some examples of usage are basically every answer to this question: Going from Curry-0, 1, 2, to ...n.

I am interested in how apply works, and I wonder if some examples are available. How could the apply procedure be re-written into another function, such as rewriting map like this?

#lang sicp

(define (map func sequence)
    (if (null? sequence) nil
        (cons (func (car sequence)) (map func (cdr sequence)))))

It seems maybe it just does a function call with the first argument? Something like:

(apply list '(1 2 3 4 5)) ; --> (list 1 2 3 4 5)
(apply + '(1 2 3))        ; --> (+ 1 2 3)

So maybe something similar to this in Python?

>>> args=[1,2,3]
>>> func='max'
>>> getattr(__builtins__, func)(*args)
3
Will Ness
  • 70,110
  • 9
  • 98
  • 181
David542
  • 104,438
  • 178
  • 489
  • 842

2 Answers2

2

apply is used when you want to call a function with a dynamic number of arguments.

Your map function only allows you to call functions that take exactly one argument. You can use apply to map functions with different numbers of arguments, using a variable number of lists.

(define (map func . sequences)
  (if (null? (car sequences))
      '()
      (cons (apply func (map car sequences))
            (apply map func (map cdr sequences)))))

(map + '(1 2 3) '(4 5 6))
;; Output: (5 7 9)
Barmar
  • 741,623
  • 53
  • 500
  • 612
1

You asked to see how apply could be coded, not how it can be used.

It can be coded as

#lang sicp

; (define (appl f xs)    ; #lang racket
;   (eval 
;     (cons f (map (lambda (x) (list 'quote x)) xs))))

(define (appl f xs)      ; #lang r5rs, sicp
  (eval
    (cons f (map (lambda (x) (list 'quote x)) 
                 xs))
    (null-environment 5)))

Trying it out in Racket under #lang sicp:

> (display (appl list '(1 2 3 4 5)))
(1 2 3 4 5)

> (display (     list   1 2 3 4 5 ))
(1 2 3 4 5)

> (appl + (list (+ 1 2) 3))
6

> (     +       (+ 1 2) 3 )
6

> (display (appl map (cons list '((1 2 3)  (10 20 30)))))
((1 10) (2 20) (3 30))

> (display (     map       list  '(1 2 3) '(10 20 30)  ))
((1 10) (2 20) (3 30))

Here's the link to the docs about eval.

It requires an environment as the second argument, so we supply it with (null-environment 5) which just returns an empty environment, it looks like it. We don't actually need any environment here, as the evaluation of the arguments has already been done at that point.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • thanks, that `5` is pretty odd in the procedure call, but it seems that's just the version (if so, why can't the implementation just figure that out itself?) Also, do you want to add a link to the answer for the `null-environment` as well? – David542 Jun 18 '21 at 16:42
  • it's the same link. :) just scroll down few lines, it's literally the next entry. :) – Will Ness Jun 18 '21 at 16:52