David542
David542

Reputation: 110123

Simplistic way to think of the apply function

In trying to 'reduce' the apply function, is the correct a proper understanding?

For example for (apply func args)

  1. Remove the (apply and matching ).
  2. Inset the func as the first element of the args, moving the outer quote in one level if necessary.

Here would be an application:

; (add-pairs '((1 2)(3 4))) --> (3 7)
(define (add-pairs ps)
  (if (null? ps) nil
     (cons (+ (car (car ps)) (cadr (car ps))) (add-pairs (cdr ps)))))
(apply add-pairs '(((1 2) (3 4))))
xxxxxxx                          x
; Remove the "(apply " and matching ")"
add-pairs '(((1 2) (3 4)))
------------^
; Insert the function into the args, moving the quote in one level if required.
(add-pairs '((1 2) (3 4)))

Is the above an accurate way to show how the apply gets added in, or am I missing anything?

Upvotes: 1

Views: 211

Answers (2)

heinwol
heinwol

Reputation: 438

It seems like you know Python. I personally think that apply in Scheme and star operator * in Python are quite similar.

Imagine you want to zip several lists, which were themselves packed inside a list. Trying to call

list_of_lists = [[1, 2],[3, 4]]
zip(list_of_lists)

would not give you [(1, 3), (2, 4)], so you write

zip(*list_of_lists)
# here it's the same as
zip(list_of_lists[0], list_of_lists[1])

using the iterable unpacking operator *. A (pretty full) alternative to this in Racket/Scheme is using an apply function:

(define list-of-lists '((1 2) (3 4)))
(apply zip list-of-lists)
;; here it's the same as
(zip (car list-of-lists) (cadr list-of-lists))

(If, of course, zip in Scheme was defined the same way as in Python, requiring arbitrary number of arguments)

But you can definitely see the difference here, the syntactic one. In Python version of apply we are 'applying' this * to arguments and then pass what was 'returned' to calling function (zip). Scheme acts like a functional language and reverses everything inside out (at least that's how I see it): you're 'applying' apply to a function and its arguments and then it handles everything itself.

The other significant difference is that, of course, apply in Scheme is a normal function, so we can write e.g.

(define (apply-func-to-sum-and-args func args)
  (func + args))
(apply-func-to-sum-and-args apply (list 1 2 3))
;; returns 6

Though I believe (correct me if I'm wrong) that this function cannot be written in pure Scheme and it calls some weird C function under the hood.

Upvotes: 1

Will Ness
Will Ness

Reputation: 71065

The example is unfortunate, as it only leaves one argument after "the opening of the parentheses". But yes, that's how I also think about it. The simpler the better, :) as long as it is correct.

Except that of course the values in the list are first evaluated, so it's not a simply-syntactical process. But as a basic example,

(apply + (list 1 2 3)) 
== 
(      +       1 2 3 )

i.e. the parens around the arguments is what goes away.

For a non-trivial example, see

Upvotes: 2

Related Questions