Calling functions
The classic approach of learning a new language is to start with syntax, data types, arithmetics and other primitives. In contrast, we will start with functions and pick up the necessary data-related components as we go.
This is how to call a function in Clojure:
(range 10)
The word range
is the function's name, and 10
is the argument. Clojure is a dialect of LISP. All its structures are so-called S-expressions. Sometimes they are also called forms. Everything is wrapped in parens: function calls, function definitions, conditionals, loops, etc.
range
is a function from clojure.core
, which, essentially, means that it's built in and comes with the language. When called with a single argument, range
returns a lazy sequence of numbers from 0 to the passed value, exclusively. (We'll talk about laziness later. Not, not because I'm lazy. I mean, not just because of thatβ¦)
To demonstrate a running Clojure code, we'll be using a REPL β an interactive shell-like interface to your Clojure programs. REPL stands for "Read, Evaluate, Print, Loop". The easiest way to play with Clojure code and a REPL is to open a REPL.it session.
At some point you should install Clojure locally (you need to install Java JDK first). Once installed, run clj
in the console. REPL.it website is handy, but your local environment will be faster and more comfortable to work with. Also, REPL.it's behavior makes it somewhat hard to quickly type in the Clojure REPL.
We can see that the sequence is another S-expression, which looks indistinguishable from a function call, as if 0
was a function's name, followed by nine numeric arguments. Keep this in mind, we'll get back to this mystery later.
Functions in Clojure may have different arities β the amount of parameters. range
has 4 arities: 0, 1, 2 and 3. Here are non-zero arities demonstrated. Try to guess what 2nd and 3rd arguments mean:
user=> (range 10)
(0 1 2 3 4 5 6 7 8 9)
user=> (range 3 10)
(3 4 5 6 7 8 9)
user=> (range 3 10 2)
(3 5 7 9)
user=> (range 3 10 3)
(3 6 9)
When there's one argument, it corresponds to the end
value. When there are two arguments, they correspond to start
and end
. The third argument specifies step
amount. If you open documentation about range
, you'll see this:
Usage: (range)
(range end)
(range start end)
(range start end step)
Returns a lazy seq of nums from start (inclusive) to end
(exclusive), by step, where start defaults to 0, step to 1,
and end to infinity. When step is equal to 0, returns an
infinite sequence of start. When start is equal to end,
returns empty list.
Everything in Clojure is an expression, so you can pass things around. Let's call another function and pass the result of range
to it:
user=> (first (range 10))
0
first
takes a sequence and returns its first element. There're also second
and last
:
user=> (second (range 3 14 2))
5
user=> (last (range 3 14 2))
13
To get an arbitrary element, use nth
, which takes 2 arguments β sequence and index:
user=> (nth (range 3 14 2) 4)
11
In case this feels confusing, here's how the same line of code would've looked in a C-like language:
nth(range(3, 14, 2), 4)
Exercises
Use your local clj
, or use the REPL above, or open a new one in a separate window. Feel free to write in the editor itself and push the "play" button, or simply use the dark, interactive panel. You can drag the divider between the editor and interactive panel to resize those areas.
Exercise 1. Call range
and pass two arguments to it:
4
- Last value of
(34 67 18 299 13)
Of course, the point is not to just put number 13, but retrieve it programmatiaclly.
When creating lists manually, you need to put '
in front of it so that Clojure knows it's a list and not a function call. Example:
(second '(34 67 18 299 13))
Exercise 2. Multiplication and other arithmetic operations in Clojure are just functions +
, *
, -
, /
. Call range
and pass it one argument:
- the multiplication of the second and the last element of
(3 2 14 29 8 18 12)
Exercise 3. Call range
and pass such arguments so that the returned result is (4 13 22 31 40 49)
.