On Application
posted by Jack Firth
Today I wanted to write about function application. Specifically, how to redefine and customize application with Racket. We’ll also look at some Racket packages that define interesting and useful forms of function application.
The theory
Application is the process of combining a function and arguments to evaluate a result. Application defines one half of lambda calculus, the formal model underlying much of modern functional programming. The other half is abstraction, which is creating new functions. Creating and applying functions is the heart of Racket and many other functional languages.
So how are functions applied in Racket? What makes (if (< 5 10) 'foo 'bar)
a macro use and (< 5 10)
a function use?
That’s actually a trick question, because function application is a macro in Racket. During macro expansion, the Racket expander inspects the first element of an expression to determine if it has a binding to a macro. If it doesn’t, rather than assume the expression is a function application, the expander inserts an artificial identifier named #%app
into the expression. So in the above example, the expression (< 5 10)
is converted to (#%app < 5 10)
. This #%app
identifier doesn’t refer to a single specific #%app
like the if
refers to if
from racket/base
, rather it refers to whatever the enclosing environment defines #%app
to be (which by default means ordinary function application from racket/base
).
However, imported modules can provide their own definitions of function application by providing an #%app
macro. Let’s define our own #%app
that, in addition to applying a function, prints out a trace message. First let’s define a helper function to implement the tracing: