This commit is contained in:
commit
95a533c876
451 changed files with 18255 additions and 0 deletions
227
docs/introduction-to-nix/nix-speedrun.md
Normal file
227
docs/introduction-to-nix/nix-speedrun.md
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
# 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).
|
||||
Loading…
Add table
Add a link
Reference in a new issue