This video is available to students only

Function definitions

There are many ways to define a function and parse arguments. In this chapter, we'll learn more about function definition, destructuring and some helpful higher-order functions.

Function definitions#

So far we have seen the usage of defn to define functions. But most of our examples were contrived and not close to real-world use cases. At work, the functions we define might need to handle a variable number of arguments, or they might need to destructure a large map passed in as an argument.

In this chapter, we'll learn various aspects of defining functions in Clojure. The examples in this chapter are coded in the first-project.fn-defs namespace.

Q. What is the disk path of the first-project.fn-defs file?

A.

Multi arity functions#

Multi arity functions accept different numbers or types of variables. They work by defining different execution paths for different arguments and are generally used to provide default arguments:

Multi arity functions are conceptually similar to function overloading.

Anonymous functions#

Anonymous (or inline) functions are functions that have no home - ie are not namespace-qualified. They exist only at the point of definition. They are useful for a variety of purposes, like defining callbacks or simple predicates.

There are two ways to define anonymous functions:

  • with fn function

  • with #() shorthand

fn and defn have similar signatures, except the function name is not present while using fn. With the shorthand, we completely skip the arguments vector and access the arguments using the %n sign, where n is the index of the argument, starting at 1.

Anonymous functions are just like normal functions and can be evaluated and called directly.

If you need to capture only one argument, you can skip the index and simply use %. Anonymous functions are helpful when working with sequence operations like map and reduce. We'll see them in action soon.

Docstrings#

Functions defined with defn or fn can follow an alternate signature to specify inline documentation:

Variable arity functions#

Variable arity or variadic functions lets you capture any number of arguments as a list. We have seen this function already, in the first-project.core namespace.

Variadic functions use & ampersand to signify a variable number of arguments:

The rest variable is available in the function scope as a list.

If we call f with five arguments: (f 1 2 3 4 5), then arg1's value will be 1 and rest will be a list of four elements: '(2 3 4 5).

apply function#

We have so far called functions by passing in the arguments manually. For example, f defined above is called by typing (f 1 2 3 4 5). But what if you wanted to call f for a list of n integers? What if these arguments were stored in a variable?

The apply function lets you "unpack" sequences and use them as function arguments.

This is the same as calling:

Except, the arguments are now a vector (or some other variable).

Destructuring arguments#

In UI programming frameworks like React, it's common to pass down props (or maps) to child components. It's also fairly common to pass configuration maps as function arguments.

Sometimes, you might need only a small part of the argument. Destructuring helps you pull out the required pieces precisely.

Vectors and lists#

Let's suppose a function that takes a three-element vector as an argument. This vector is fetched directly from the database and holds the name, age and height in cms of a user, in that order. If we wanted to get the name, age and height with what we know so far, we could write something like:

This doesn't spark joy. With sequence destructuring, the same code can be rewritten as:

 

This page is a preview of Tinycanva: Clojure for React Developers

Please select a discussion on the left.