227 lines
4 KiB
Markdown
227 lines
4 KiB
Markdown
# Nix Speedrun
|
|
|
|
This section will cover some Nix language basics as fast as possible.
|
|
|
|
## Comments
|
|
|
|
```nix
|
|
# This is a comment
|
|
|
|
/*
|
|
This is a block comment
|
|
*/
|
|
```
|
|
|
|
## Data types
|
|
|
|
Every value in Nix has a type. Some basic types are:
|
|
|
|
```nix
|
|
16 # integer
|
|
|
|
3.14 # float
|
|
|
|
false # boolean
|
|
|
|
"Hello, world!" # string
|
|
|
|
''
|
|
This is also a string,
|
|
but over multiple lines!
|
|
''
|
|
```
|
|
|
|
Assign a value to a variable:
|
|
|
|
```nix
|
|
myVar = "99";
|
|
```
|
|
|
|
And then inject it into a string:
|
|
|
|
```nix
|
|
''
|
|
I got ${myVar} problems,
|
|
but Nix ain't one.
|
|
''
|
|
```
|
|
|
|
Nix also has compound values. This is a list:
|
|
|
|
```nix
|
|
[ 123 "hello" true null [ 1 2 ] ]
|
|
```
|
|
|
|
You can mix different types in a list. This is an attribute set:
|
|
|
|
```nix
|
|
{
|
|
foo = 4.56;
|
|
bar = {
|
|
baz = "this";
|
|
qux = false;
|
|
};
|
|
}
|
|
```
|
|
|
|
An attribute set is like an object. It is a collection of name-value-pairs called *attributes*. The expression above is equivalent to:
|
|
|
|
```nix
|
|
{
|
|
foo = 4.56;
|
|
bar.baz = "this";
|
|
bar.qux = false;
|
|
}
|
|
```
|
|
|
|
## Evaluation
|
|
|
|
In Nix, everything is an expression that evaluates to a value. Create a `hello.nix`-file with the following content:
|
|
|
|
```nix
|
|
"Hello, world!"
|
|
```
|
|
|
|
Then, evaluate the file:
|
|
|
|
```bash
|
|
nix eval --file hello.nix
|
|
```
|
|
|
|
```
|
|
Hello, world!
|
|
```
|
|
|
|
A let-expression allows you to define local variables for an expression:
|
|
|
|
```nix
|
|
let
|
|
alice = {
|
|
name = "Alice";
|
|
age = "26";
|
|
};
|
|
in
|
|
''
|
|
Her name is ${alice.name}.
|
|
She is ${alice.age} years old.
|
|
''
|
|
```
|
|
|
|
## Functions
|
|
|
|
Functions have the following form:
|
|
|
|
```nix
|
|
pattern: body
|
|
```
|
|
|
|
The pattern specifies what the argument of the function must look like, and binds variables in the body to (parts of) the argument.
|
|
|
|
```nix
|
|
let
|
|
increment = num: num + 1;
|
|
in
|
|
increment 49
|
|
```
|
|
|
|
Functions can only have a single argument. For multiple arguments, nest functions:
|
|
|
|
```nix
|
|
let
|
|
isAllowedToDrive =
|
|
name: age:
|
|
if age >= 18 then "${name} is eligible to drive." else "${name} is too young to drive yet.";
|
|
in
|
|
isAllowedToDrive "Charlie" 19
|
|
```
|
|
|
|
It is common to pass multiple arguments in an attribute set instead. Since Nix is lazily evaluated, you can define multiple bindings in the same let-statement.
|
|
|
|
```nix
|
|
let
|
|
add = { a, b }: a + b;
|
|
result = add { a = 34; b = 35; };
|
|
in
|
|
result
|
|
```
|
|
|
|
You can also set optional arguments by providing default values:
|
|
|
|
```nix
|
|
let
|
|
greet = { greeting ? "Hello", name }: "${greeting}, ${name}!";
|
|
in
|
|
greet { name = "Bob"; }
|
|
```
|
|
|
|
Let's look at one last example:
|
|
|
|
```nix
|
|
let
|
|
myFunc = { a, b, c }: a + b * c;
|
|
|
|
numbers = {
|
|
a = 1;
|
|
b = 2;
|
|
c = 3;
|
|
};
|
|
|
|
result = myFunc { a = numbers.a; b = numbers.b; c = numbers.c; };
|
|
in
|
|
result
|
|
```
|
|
|
|
Nix provides some syntactical sugar to simplify that function call. The `with` keyword brings all attributes from an attribute set into the scope:
|
|
|
|
```nix
|
|
# ...
|
|
result = with numbers; myFunc { a = a; b = b; c = c; };
|
|
# ...
|
|
```
|
|
|
|
However, this syntax is discouraged. Use `inherit` instead to explicitly list attributes to bring into the scope:
|
|
|
|
```nix
|
|
# ...
|
|
inherit (numbers) a b c;
|
|
result = myFunc { inherit a b c; };
|
|
# ...
|
|
```
|
|
|
|
## Builtin functions
|
|
|
|
Nix provides [builtin functions](https://nix.dev/manual/nix/2.25/language/builtins) by default through the global `builtins` constant. For example, `builtins.attrNames` gives you a list of all attributes of the given attribute set:
|
|
|
|
```nix
|
|
builtins.attrNames { a = 1; b = 2; }
|
|
# => [ "a" "b" ]
|
|
```
|
|
|
|
> Yes, this means that attribute keys, though defined as variables, are available as strings.
|
|
|
|
Some builtins are so common that the `builtins` prefix can be omitted. `map` is a builtin function that applies a function to each element of a list.
|
|
|
|
```nix
|
|
# squares.nix
|
|
let
|
|
numbers = [ 5 2 1 4 3 ];
|
|
squares = map (n: n * n) numbers;
|
|
in
|
|
{
|
|
inherit numbers squares;
|
|
}
|
|
```
|
|
|
|
The `import` function allows to separate the codebase into multiple files:
|
|
|
|
```nix
|
|
# sort.nix
|
|
let
|
|
results = import ./squares.nix; # paths have their own type
|
|
inherit (results) squares;
|
|
inherit (builtins) sort lessThan;
|
|
in
|
|
sort lessThan squares
|
|
```
|
|
|
|
> The `sort` function can be found in the [Nix manual](https://nix.dev/manual/nix/2.25/language/builtins#builtins-sort).
|