Summary: Function application is a key concept in lambda calculus. While it is commonly expressed using parentheses in Clojure, it is also reified into a function which itself can be applied to another function.
Function application in Clojure is easily expressed with a couple of parentheses:
(foo 1 2 3)
That's the function
foo applied to the arguments
But let's say we have those numbers in a
vector somewhere, and we want to
foo on them.
(def some-numbers [1 2 3])
We could manually pull out the arguments from the vector like this:
(foo (some-numbers 0) (some-numbers 1) (some-numbers 2))
Great! That should work. But more commonly you see this:
(apply foo some-numbers)
apply means take the function (the first argument) and apply it to the
arguments which are in the list (the last argument).
apply pulls out
the values from the list internally so you don't have to.
apply is a function you'll see in many Lisps. It plays a key role in
defined in The Structure and Interpretation of Computer Programs
(SICP). In the meta-circular evaluator,
apply are defined
in terms of each other.
eval is defined classically,
(foo 1 2 3) gets turned into
(apply foo [1 2 3]) internally. This means that you can replace
(foo 1 2 3) with
(apply foo [1 2 3]) in the program without changing
apply is a function,
(apply foo [1 2 3]) is equivalent to
(apply apply [foo [1 2 3]]), which is equivalent to
(apply apply [apply [foo [1 2 3]]]). And you can expand that out
forever. (Please don't!).
apply is something I really love about Lisp. It takes one of the
main parts of lambda calculus (function application) and
reifies it. Function application is available as a
function, which can be passed around, composed, etc, just like any
other value. I love it!
If you're in love with this idea, too, you might want to check out LispCast Introduction to Clojure. It's my video course about, you guessed it, Clojure. It takes you from absolute parenthesis-phobe to I-never-knew-it-could-be-this-way lisper by using animations, exercises, and screencasts.