Functions are a crucial part of every programmer’s day job, when talking about a function, it can be defined as a set of instructions that MUST perform a specific task together and if you want, can be referred under an identifier.
For those who already know the basics of a programming language, it isn’t a new technique, almost all programming languages have some way to create your own functions. Clojure as a functional programming language, has functions on its core (as the name suggests), a software written using it, can be seen as a set of functions that together perform a task.
A function in a beautiful blueprint can be drawn as a magic black box that receives inputs and produces outputs, for example, we have a black box, that we sent 2 and 2 to it, and the output is 4, therefore, we can conclude that inside that box has a mechanism to sum the given
In Clojure to create a new function, we can use
fn, fallowed by its params inside square brackets, and its body when you place your operations.
To create a function that prints a hello with a given name, we just need to type:
=> (fn [name] (println "Hello" name))
Now we have our function, that’s great! But how do we call it?
Using this way we’re creating what are called “anonymous functions” and this name is given because this function doesn’t have a name to be called later, and if we want to use it, we need to evaluate it and pass its arguments.
=> ((fn [name] (println "Hello" name)) "Gabi") "Hello Gabi"
In that way, Clojure will evaluate our function first, and then call it with our given arguments.
Anonymous function has a short way of be created to, and its using
#(), our previous example will look like this in the shorter way:
(#(println "Hello" %) "Gabriela")
Note that our parameter is referred as
% inside our anonymous function in that way, if we have more parameters to our function it can be referred as
%n, and we can use
%& to refer to the “rest”.
If we want to bind an anonymous function to an identifier to refer later, we can use the
def that we already learned in past posts, to bind our anonymous function to a name.
=> (def say-hello (fn [name] (println "Hello" name))) #'user/say-hello (say-hello "Gabriela") => "Hello Gabriela"
This is awesome, now we can use our function how many times we want, with different parameters:
=> (say-hello "Otavio") "Hello Otavio" => (say-hello "V") "Hello V"
Fortunately, to avoid write
def fallowed by
fn every time, Clojure has
defn that will act as a fusion of
fn that we previous used:
Our say-hello the function will look like this:
=> (defn say-hello [name] (println "Hello" name)) #'user/say-hello => (say-hello "Clojure") "Hello Clojure"
Now we know a new spell that we can use every time that we’re playing with magic! We can write our “black box” function from the first example, like this:
=> (defn sum [x y] (+ x y)) #'user/sum => (sum 2 2) 4
Now every time makes sense right?
This example can lead us to another interesting thing in Clojure, a function will always return its last evaluated instruction, what it means? A function will always return something, our
sum function (last example) will return the sum of
(+ x y) it’s our last evaluated expression.
Clojure treats its functions as what we call “first-class citizens” and it means that we can return functions from functions, bind it (store at variable), store it at a data structure, and pass functions as an argument to other functions, that’s great right? Too much power to use while creating new spells.
Functions like our sum that always returns the same value for the same arguments is called pure functions, in a beautiful world, it would be the only kind of functions, we always want to work with pure functions because it’s returned value is predictable. Unfortunately, we have the dark side, “impure functions” which is basically a function that can return different values for the same arguments and can return unexpected values.
Let’s take a look at an example, what of these functions can you always preview the value returned?
The first one just multiply two values, with we send it two numbers it will work, for example, if we call it with
2 it will always return
4, we can always predict its return value and its awesome, we have a pure function.
The second function of the draw, if impure, the function
read-line, will take a input from user, and we can’t predict its return value, the user can input anything when asked, and we can’t preview it.
When writing good software is a good architecture pattern to isolate impure functions, so you can correctly handle it, expecting errors and much more.
When writing software is always good to find a balance when your software is correctly documented, Clojure provides a beautiful way to document part of your software with docstrings on function declarations, just add your doc before function parameters, like that:
(defn sum "Sum `x` and `y`" [x y] (+ x y))
When we learn more about namespaces we’ll learn how much it can be useful to document public functions.
You can read a function doc with
doc spell, just use it with the function name, if its contains doc, it will be displayed:
=> (doc sum) ------------------------- user/sum ([x y]) Sum `x` and `y` nil
When use anonymous functions
Anonymous functions look good, but some people have the question “If I can create a named function and call it everywhere, why should I need it?”, well, it’s a good question. It can be used in a lot of ways, mostly when dealing with functions that returns or receive functions, or in specific cases when you need to write a short function.
The most common example is with
map (that we learned how to use in the previous post), sometimes you’ll want to apply a simple function to a sequence and don’t want to create a named function, for example:
=> (map #(str "Hey " % ", how you doin?") ["Otavio" "V" "Gabi"]) ("Hey Otavio, how you doin?" "Hey V, how you doin?" "Hey Gabi, how you doin?")
Know when to use short anonymous functions is a great skill for a little wizard.
Functions are essential, especially in a functional language, it’s a core feature in almost all programming languages and is a part of every developer day, learn and understand how to use it will be great and will help a lot when developing.
We as Clojure wizards can create a lot of new, useful and powerful spells now.
On the next post of this series, we’ll keep talking about functions, but more features around it that can help you a lot.
If you have any questions that I can help you with, please ask! Send an email (otaviopvaladares at gmail.com), pm me on my Twitter, or comment on this post!
Follow my blog to get notified every new post: