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.
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
racket/base, rather it refers to whatever the enclosing environment defines
#%app to be (which by default means ordinary function application from
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:
~v to more clearly see the difference between strings, symbols, and numbers. Now, we can write a macro to insert a call to our function wherever we use the macro:
This macro is very simple, and on it’s own isn’t really useful at all (we could just call
trace directly). However, we can provide this macro with the name
#%app to trigger the automatic use of
trace-app whenever a function call is written. We’ll move our
trace-app definitions into a submodule to see this in action without multiple files:
Now, with a simple
require statement and these seven lines of code, we can trace the order of evaluation of all expressions in a Racket module.
#%app is occasionally used when defining new languages, but a much more pedestrian use is to add some notational shorthand to make certain constructs more convenient. For example, consider the
fancy-app package. This package provides an
#%app macro that behaves just like normal function application unless one or more underscores are used. In that case, the function application is converted to a lambda that takes as input one argument for each underscore. For example,
(format "Hello ~a" _) is equivalent to
(lambda (v) (format "Hello ~a" v)). This is especially useful for whipping up quick lambdas as arguments to functions like
rackjure package redefines
#%app to make working with nested dictionaries easier. Dictionaries can be used to get and set values for keys when used as procedures, and when dictionaries are the second value of a function application the first value is interpreted as a key and the dictionary’s associated value is looked up. See the
rackjure documentation for details.