nix-book/source/nix-language/functions.adoc
2023-12-02 17:32:03 +00:00

173 lines
4.3 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]
....
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.
Note that the message printed by the NixREPL 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]
....
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]
....
nix-repl> f = x: x + 1
nix-repl> f
«lambda @ «string»:1:2»
....
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]
....
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]
....
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!
[source]
....
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]
....
nix-repl> (add 3) 5
8
....
In fact, the parentheses aren't needed.
[source]
....
nix-repl> add 3 5
8
....
In case that wasn't clear, let's repeat those steps, but 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]
....
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]
....
nix-repl> :t g
a function
....
Now we can apply `g` to a number to get a new number.
[source]
....
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.
To specify an attribute set as a parameter, we use a _set pattern_,
which has the form
{ _name1_, _name2_, ... }
Note that while the key-value associations in attribute sets are separated by semi-colons,
the key names in the attribute _set pattern_ are separated by commas.
Here's an example.
[source]
....
nix-repl> greet = { first, last }: "Hello ${first} ${last}! May I call you ${first}?"
nix-repl> greet { first="Amy"; last="de Buitléir"; }
"Hello Amy de Buitléir! May I call you Amy?"
....
== Optional parameters
We can make some values in an attribute set optional by providing default values,
using the syntax `_name_ ? _value_`.
This is illustrated below.
[source]
....
nix-repl> greet = { first, last ? "whatever-your-lastname-is", topic ? "Nix" }: "Hello ${first} ${last}! May I call you ${first}? Are you enjoying learning ${topic}?"
nix-repl> greet { first="Amy"; }
"Hello Amy whatever-your-lastname-is! May I call you Amy? Are you enjoying learning Nix?"
nix-repl> greet { first="Amy"; topic="Mathematics";}
"Hello Amy whatever-your-lastname-is! May I call you Amy? Are you enjoying learning Mathematics?"
....
== @-patterns
TODO
TODO
TODO
TODO
TODO