Why should I use 'apply' in Clojure?

This is what Rich Hickey said in one of the blog posts but I don't understand the motivation in using apply. Please help.

A big difference between Clojure and CL is that Clojure is a Lisp-1, so funcall is not needed, and apply is only used to apply a function to a runtime-defined collection of arguments. So, (apply f [i]) can be written (f i).

Also, what does he mean by "Clojure is Lisp-1" and funcall is not needed? I have never programmed in CL.

Thanks


Solution 1:

You would use apply, if the number of arguments to pass to the function is not known at compile-time (sorry, don't know Clojure syntax all that well, resorting to Scheme):

(define (call-other-1 func arg) (func arg))
(define (call-other-2 func arg1 arg2) (func arg1 arg2))

As long as the number of arguments is known at compile time, you can pass them directly as is done in the example above. But if the number of arguments is not known at compile-time, you cannot do this (well, you could try something like):

(define (call-other-n func . args)
  (case (length args)
    ((0) (other))
    ((1) (other (car args)))
    ((2) (other (car args) (cadr args)))
    ...))

but that becomes a nightmare soon enough. That's where apply enters the picture:

(define (call-other-n func . args)
  (apply other args))

It takes whatever number of arguments are contained in the list given as last argument to it, and calls the function passed as first argument to apply with those values.

Solution 2:

The terms Lisp-1 and Lisp-2 refer to whether functions are in the same namespace as variables.

In a Lisp-2 (that is, 2 namespaces), the first item in a form will be evaluated as a function name — even if it's actually the name of a variable with a function value. So if you want to call a variable function, you have to pass the variable to another function.

In a Lisp-1, like Scheme and Clojure, variables that evaluate to functions can go in the initial position, so you don't need to use apply in order to evaluate it as a function.

Solution 3:

apply basically unwraps a sequence and applies the function to them as individual arguments.

Here is an example:

(apply + [1 2 3 4 5])

That returns 15. It basically expands to (+ 1 2 3 4 5), instead of (+ [1 2 3 4 5]).