Nix Language
Nix Language
Introduction
With the Nix package manager, there always comes the Nix programming lanugage. This is a programming language specificly created for the Nix package manager. To launch an interactive repl, run:
$ nix repl
nix-repl> 1 + 2
3
nix-repl>:q
$
The Nix programming language uses lazy evaluation. This means that values only get computed when needed. This is quite useful since it allows for resource efficient recursive functions and other stuff used in functional programming languages. This can be seen in action using something like this:
$ nix repl
nix-repl> { a.b.c = 1; }
{a = { ... }; }
nix-repl>:p { a.b.c = 1; }
{a = { b = { c = 1; }; }; }
Notice how we needed to use the :p to tell Nix that we actually want to see
everything and not just the evaluated data structure.
Running/Evaluating Nix files
Until now, we only used the nix repl command to launch an interactive
interpreter to get started. We can automate this by creating a file.nix.
Please note, that your file can be named differently and doesn't need to be
named file.nix:
$ echo 1 + 1 > file.nix
$ nix-instantiate --eval file.nix
3
Using the nix-instantiate command with the --eval flag, we can only
evaluate the file. If we didn't use that flag, Nix would expect a
derivation. What a derivation is, will be explained later. For now, just
know that this is the same as running the commands in the nix repl.
In here, we can see the lazy evaluation in action. If we run:
$ echo "{ a.b.c = 1; }" > file.nix
$ nix-instantiate --eval file.nix
{ a = <CODE>; }
You can see, that the output is a bit weird and doesnt really show the actual
value, but rather { a = <CODE>; }. To fix this, we can use the --strict
flag:
$ echo "{ a.b.c = 1; }" > file.nix
$ nix-instantiate --eval --strict file.nix
{ a = { b = { c = 1; }; }; }
Comments
Comments in Nix are declared with #:
{
string = "hello";
# This is a comment
}
Data types
In nix, there are various data types. Those include:
- Primitive: boolean, integers, floats ...
- Lists: A list of a datatype
- Attribute sets: A collection of name-value-pairs.
- Functions:
Primitive
There are multiple primitive data types in Nix:
myString = "hello";
myInteger = 1;
myFloat = 3.141;
myBool = true;
myNull = null;
List
A list is almost like an array in other languages. In Nix, a list however can
contain any type. Also values are not seperated by a , but rather by a
whitespace:
myList = [ 1 "two" false ];
Attribute set
An attribute set is a collection of name-value-pairs. A given name must be unique in the set. It is comparable with a json file:
{
string = "hello";
integer = 1;
float = 3.141;
bool = true;
null = null;
list = [ 1 "two" false ];
attribute-set = {
a = "hello";
b = 2;
c = 2.718;
d = false;
};
}
Recursive attribute set
To make an attribute set be able to use its own variables, we need to use the
rec { ... } keyword. This allowes the access to those attributes.
rec {
one = 1;
two = one + 1;
three = two + 1;
}
Attribute access
To get a value out of an attribute set, use . and the attribute name:
let
attribute-set = {
a = {
x = 1;
};
};
in
attribute-set.a.x
Let ... in ...
This is used for declaring types, which are later reused. Assignments are placed
between the let and in keywords. In the following example, a is assigned
to 1. After in comes the expression in which the variables are used. a in
here refers to a = 1:
let
a = 1;
b = 2;
c = a + b;
in
a + b + c
Output:
6
with ...; ...
This keyword allows access to attributes without the need to reference the
attribute set for each value. This means instead of writing something like
attribute-set.nested-attribute-set.value we can use:
let
attribute-set = {
nested-attribute-set = {
value = 1;
};
};
in
with attribute-set.nested-attribute-set; value
Functions
Functions in Nix are defined like this:
let
myFunction = x: x + 1;
in
myFunction 1
To access values in a attribute set use:
let
myFunction = x: x.a;
in
myFunction { a = 1; }
Function examples
The following section provides some examples on how to write a function in Nix. Due to the fact that functions only can take one argument in Nix, these examples might be useful.
- Single argument
x: x + 1
- Multiple arguments via nesting
x: y: x + y
- Multiple arguments via an attribute set
{ a, b }: a + b
- Multiple arguments with default values declared
{ a, b ? 0}: a + b
- Multiple arguments with additional attributes allowed
{ a, b, ...}: a + b
- Named attribute set
{ a, b, ...}@args: a + b + args.c
Builtin functions
Nix comes with many functions out of the box. Those all are implemented in C++ as part of the Nix language interpreter. A full list of all the functions can be found here
Some examples are:
builtins.toString: Converts a value to a stringimport: Imports another file
See also
This is just a short guide/wiki entry on how to use the basics of the Nix programming language. A more extensive guide can be found on the official documentation for the Nix ecosystem.