Nix 101: Part 1
This post goes over the basics of the Nix Language and in later posts will cover the applications of Nix.
What is Nix?
Nix is a system to create reproducible builds and shell environments. Nix has a purely functional language to express the building of reproducible shell environments.
This post will go over the basics of the language.
Variables
Nix has basic variables found in most high level languages.
string = "Hello, World!";
integer = 1;
bool = true;
list = [1 2 3];
Variables - let..in..
Variables can be defined using the let ... in ...
syntax.
The variables are defined in the let
scope and then used for evaluation in the in
scope.
let
x = 1;
y = 2;
in
x + y
>> 3
Strings
String interpolation is achieved using ${variable}
let
name = "Foo";
in
"hello ${name}"
Lists
Lists can be declared using []
.
[1 2 3];
Attributes
Attributes are a datastructure, similar to JSON. They are defined using {}
and
have named key values.
The values can be accessed using dot notation to refer to a key name.
let
attributes = { x = 1; y = 2; };
in
attributes.x + attributes.y
>> 3
Recursive Attributes
Recursive Attributes allows the variables within a scope to be referenced using
the rec
keyword.
rec {
one = 1;
two = one + 1;
three = two + 1;
}
With
Atrributes can be accessed more easily using the with
keyword.
with
allows access to the attirbutes values without needing to use dot notation.
let
a = {
x = 1;
y = 2;
z = 3;
};
in
with a; [x y z]
Functions
Functions in Nix are lambda functions with a :
separating arguments from the function body.
x: x + 1
Attribute sets can be used as arguments.
{a, b}: a + b
Default/optional arguments can be provided using ?
.
{a, b ? 0}: a + b
Named arguments can be given using the @
symbol.
args@{a, b, ...}: a + b + args.c
Using let..in.., we can define a function and then call it.
let
f = x: x + 1;
in
f 1
We can also pass an attribute set as an argument, which seems to be a common pattern in Nix.
let
f = x: x.a + 1;
in
f { a = 1; }
We can also declare functions and variables in the let scope and then apply them.
let
f = x: x.a + 1;
v = { a = 1; };
in
f v
Functions can also be immediately callable by wrapping it around ()
(x: x + 1) 1
Functions can be passed to list and have the function evaluated and the result stored in the list.
let
f = x: x + 1;
a = 1;
in [ (f a) ]
Functions can also be passed with out being evaluated along side the arguments.
let
f = x: x + 1;
a = 1;
in [ f a ]
Single attribute sets with multiple values can be used as the argument, as mentioned earlier, this is a common pattern.
let
f = {a, b}: a + b
in
f { a = 1; b = 1; };
Inherit
This keyword is shorthand for assigning variables from the previous scope into the new scope.
The below is the equivalent of:
x = a.x;
y = a.y;
let
a = { x = 1; y = 2; };
in
{
inherit (a) x y;
}
Summary
Nix is a reproducible build system for shells and environments. Nix uses a functional programming language to express and evaluate reproducible builds.