nix-book/source/nix-language/functions.adoc
Amy de Buitléir d0be400f85 expanded
2025-10-12 15:58:37 +01:00

164 lines
4.4 KiB
Text

[#functions]
= Functions
== Anonymous functions
Functions are defined using the syntax `_parameter_: _expression_`,
where the _expression_ typically involves the _parameter_.
Consider the following example.
[source]
.Example
....
nix-repl> x: x + 1
«lambda @ «string»:1:1»
....
We created a function that adds `1` to its input.
However, it doesn't have a name, so we can't use it directly.
Anonymous functions do have their uses, as we shall see shortly.
// TODO Add a cross-reference to "shortly"
// TODO Show that you can pass a function to a function
Note that the message printed by the Nix REPL when we created the function uses the term _lambda_.
This derives from a branch of mathematics called _lambda calculus_.
Lambda calculus was the inspiration for most functional languages such as Nix.
Functional programmers often call anonymous functions "lambdas".
The Nix REPL confirms that the expression `x: x + 1` defines a function.
[source]
.Example
....
nix-repl> :t x: x + 1
a function
....
== Named functions and function application
How can we use a function?
Recall from <<type-lambda>> that functions can be treated like any other data type.
In particular, we can assign it to a variable.
[source]
.Example
....
nix-repl> f = x: x + 1
nix-repl> f
«lambda @ «string»:1:2»
....
// TODO Show that you can pass a function to a function
Procedural languages such as C or Java often use parenthesis to apply a function to a value, e.g. `f(5)`.
Nix, like lambda calculus and most functional languages, does not require parenthesis for function application.
This reduces visual clutter when chaining a series of functions.
Now that our function has a name, we can use it.
[source]
.Example
....
nix-repl> f 5
6
....
== Multiple parameters using nested functions
Functions in Nix always have a single parameter.
To define a calculation that requires more than one parameter,
we create functions that return functions!
[source]
.Example
....
nix-repl> add = a: (b: a+b)
....
We have created a function called `add`.
When applied to a parameter `a`, it returns a new function that adds `a` to its input.
Note that the expression `(b: a+b)` is an anonymous function.
We never call it directly, so it doesn't need a name.
Anonymous functions are useful after all!
I used parentheses to emphasise the inner function, but they aren't necessary.
More commonly we would write the following.
[source]
.Example
....
nix-repl> add = a: b: a+b
....
If we only supply one parameter to `add`, the result is a new function rather than a simple value.
Invoking a function without supplying all of the expected parameters is called _partial application_.
[source]
.Example
....
nix-repl> add 3 # Returns a function that adds 3 to any input
«lambda @ «string»:1:6»
....
Now let's apply `add 3` to the value `5`.
[source]
.Example
....
nix-repl> (add 3) 5
8
....
In fact, the parentheses aren't needed.
[source]
.Example
....
nix-repl> add 3 5
8
....
If you've never used a functional programming language, this all probably seems very strange.
Imagine that you want to add two numbers, but you have a very unusual calculator labeled "add".
This calculator never displays a result, it only produces more calculators!
If you enter the value `3` into the "add" calculator, it gives you a second calculator labeled "add 3".
You then enter `5` into the "add 3" calculator, which displays the result of the addition, `8`.
With that image in mind, let's walk through the steps again in the REPL, but this time in more detail.
The function `add` takes a single parameter `a`,
and returns a new function that takes a single parameter `b`, and returns the value `a + b`.
Let's apply `add` to the value `3`, and give the resulting new function a name, `g`.
[source]
.Example
....
nix-repl> g = add 3
....
The function `g` takes a single parameter and adds `3` to it.
The Nix REPL confirms that `g` is indeed a function.
[source]
.Example
....
nix-repl> :t g
a function
....
Now we can apply `g` to a number to get a new number.
[source]
.Example
....
nix-repl> g 5
8
....
== Multiple parameters using attribute sets
I said earlier that a function in Nix always has a single parameter.
However, that parameter need not be a simple value; it could be a list or an attribute set.
This approach is widely used in Nix, and the language has some special features to support it.
This is an important topic, so we will cover it separately in <<argument-sets>>.