initial commit

This commit is contained in:
Amy de Buitléir 2023-12-01 18:32:34 +00:00
parent 3d00d41153
commit 3bda18c1db
14 changed files with 533 additions and 0 deletions

View file

@ -0,0 +1,34 @@
= Attribute set operations
The `.` operator selects an attribute from a set.
[source]
....
nix-repl> animal = { name = { first = "Professor"; last = "Paws"; }; age = 10; species = "cat"; }
nix-repl> animal . age
10
nix-repl> animal . name . first
"Professor"
....
We can use the `?` operator to find out if a set has a particular attribute.
[source]
....
nix-repl> animal ? species
true
nix-repl> animal ? bicycle
false
....
We can use the `//` operator to modify an attribute set.
Recall that Nix values are immutable, so the result is a new value (the original is not modified).
[source]
....
nix-repl> animal // { species = "tiger"; }
{ age = 10; name = { ... }; species = "tiger"; }
....

View file

@ -0,0 +1,50 @@
# Boolean operations
The usual boolean operators are available.
Recall that earlier we set `a = 7` and `b = 3`.
[source]
....
nix-repl> a == 7 # equality test
true
nix-repl> b != 3 # inequality
false
nix-repl> a > 12 # greater than
false
nix-repl> b >= 2 # greater than or equal
true
nix-repl> a < b # less than
false
nix-repl> b <= a # less than or equal
true
nix-repl> !true # logical negation
false
nix-repl> (3 * a == 21) && (a > b) # logical AND
true
nix-repl> (b > a) || (b > 10) # logical OR
false
....
One operator that might be unfamiliar to you is _logical implication_, which uses the symbol `->`.
The expression `u -> v` is equivalent to `!u || v`.
[source]
....
nix-repl> u = false
nix-repl> v = true
nix-repl> u -> v
true
nix-repl> v -> u
false
....

View file

@ -0,0 +1,6 @@
= Built-in functions
// TODO
For a complete list of built-in functions, see
https://nixos.org/manual/nix/stable/language/builtins

View file

@ -0,0 +1,31 @@
= Stop reading this chapter!
When I first began using Nix, it seemed logical to start by learning the Nix language.
However, after following an in-depth tutorial,
I found that I didn't know how to do anything useful with the language!
It wasn't until later that I understood what I was missing:
a guide to the most useful library functions.
When working with Nix or NixOS,
it's very rare that you'll want to write something from scratch.
Instead, you'll use one of the many library functions
that make things easier and shield you from the underlying complexity.
Many of these functions are language-specific,
and the documentation for them may be inadequate.
Often the easiest (or only) way to learn to use them
is to find an example that does something similar to what you want,
and then modify the function parameters to suit your needs.
At this point you've learned enough of the Nix language
to do the majority of common Nix tasks.
So when I say "Stop reading this chapter!", I'm only half-joking.
Instead I suggest that you _skim_ the rest of this chapter,
paying special attention to anything marked with icon:exclamation-circle[].
Then move on to the following chapters
where you will learn how to develop and package software using Nix.
Afterward, come back to this chapter and read it in more detail.
While writing this book, I anticipated that readers would want to skip around,
alternating between pure learning and learning-by-doing.
I've tried to structure the book to support that;
sometimes repeating information from earlier chapters that you might have skipped.

View file

@ -0,0 +1,3 @@
= Functions
// TODO

View file

@ -0,0 +1,16 @@
= Introducing the Nix language
Nix and NixOS use a functional programming language called _Nix_
to specify how to build and install software,
and how to configure system, user, and project-specific environments.
(Yes, “Nix” is the name of both the package manager and the language it uses.)
Nix is a _functional_ language.
In a _procedural_ language such as C or Java,
the focus is on writing a series of _steps_ (statements) to achieve a desired result.
By contrast, in a functional language the focus is on _defining_ the desired result.
In the case of Nix, the desired result is usually a _derivation_:
a software package that has been built and is ready for use.
The Nix language has been designed for that purpose,
and thus has some features you don't typically find in general-purpose languages.

View file

@ -0,0 +1,9 @@
= List operations
Lists can be concatenated using the `++` operator.
[source]
....
nix-repl> [ 1 2 3 ] ++ [ "apple" "banana" ]
[ 1 2 3 "apple" "banana" ]
....

View file

@ -0,0 +1,27 @@
= The Nix language
include::intro.adoc[leveloffset=+1]
include::types.adoc[leveloffset=+1]
include::dont-read.adoc[leveloffset=+1]
include::repl.adoc[leveloffset=+1]
include::variables.adoc[leveloffset=+1]
include::numbers.adoc[leveloffset=+1]
include::strings.adoc[leveloffset=+1]
include::booleans.adoc[leveloffset=+1]
include::paths.adoc[leveloffset=+1]
include::lists.adoc[leveloffset=+1]
include::attribute-sets.adoc[leveloffset=+1]
include::functions.adoc[leveloffset=+1]
include::builtins.adoc[leveloffset=+1]

View file

@ -0,0 +1,83 @@
# Numeric operations
The usual arithmetic operators are provided.
[source]
....
nix-repl> 1 + 2 # addition
3
nix-repl> 5 - 3 # subtraction
2
nix-repl> 3 * 4 # multiplication
12
nix-repl> 6 / 2 # division
3
nix-repl> -1 # negation
-1
....
[IMPORTANT]
====
The spaces before and after operators aren't always required.
However, you can get unexpected results when you omit them, as shown below.
[source]
....
nix-repl> 6/2
/home/amy/codeberg/nix-book/6/2
....
What happened?
Let's use the `:t` command to find out the type of the expression.
[source]
....
nix-repl> :t 6/2
....
If an expression can be interpreted as a path, Nix will do so.
This is useful, because paths are _far_ more commonly used in Nix expressions that arithmetic operators.
In this case, Nix interpreted `6/2` as a relative path from the current directory,
which in the above example was `/home/amy/codeberg/nix-book`.
Adding a space after the `/` operator produces the expected result.
[source]
....
nix-repl> 6/ 2
3
....
To avoid surprises and improve readability, I prefer to use spaces before and after all operators.
====
Numbers without a decimal point are assumed to be integers.
To ensure that a number is interpreted as a floating-point value, add a decimal point.
[source]
....
nix-repl> :t 5
an integer
nix-repl> :t 5.0
a float
nix-repl> :t 5.
a float
....
In the example below, the first expression results in integer division (rounding down),
while the second produces a floating-point result.
[source]
....
nix-repl> 5 / 3
1
nix-repl> 5.0 / 3
1.66667
....

View file

@ -0,0 +1,65 @@
= Path opearations
Paths can be concatenated with each other to produce a new path.
[source]
....
nix-repl> /home/wombat + /bin/sh
/home/wombat/bin/sh
nix-repl> :t /home/wombat + /bin/sh
a path
....
[IMPORTANT]
====
Relative paths become absolute when they are parsed, which occurs before concatenation.
This is why the result in the example below is not `/home/amy/file.txt`.
[source]
....
nix-repl> /home/wombat + ./file.txt
/home/wombat/home/amy/codeberg/nix-book/file.txt
....
====
A path can be concatenated with a string to produce a new path.
[source]
....
nix-repl> homePath + "/file.txt"
/home/wombat/file.txt
nix-repl> :t homePath + "/myfile.txt"
a path
....
[NOTE]
====
The Nix reference manual says that the string must not "have a string context" that refers to a store path.
String contexts are beyond the scope of this book;
for more information see https://nixos.org/manual/nix/stable/language/operators#path-concatenation.
====
Strings can be concatenated with paths, but with a side-effect that may surprise you:
if the path exists, the file is copied to the Nix store!
The result is a string, not a path.
In the example below, the file `file.txt` is copied to `/nix/store/gp8ba25gpwvbqizqfr58jr014gmv1hd8-file.txt`
(not `/home/wombat/nix/store/gp8ba25gpwvbqizqfr58jr014gmv1hd8-file.txt`).
[source]
....
nix-repl> "/home/wombat" + ./file.txt
"/home/wombat/nix/store/gp8ba25gpwvbqizqfr58jr014gmv1hd8-file.txt"
....
The path must exist.
[source]
....
nix-repl> "/home/wombat" + ./no-such-file.txt
error (ignored): error: end of string reached
error: getting status of '/home/amy/codeberg/nix-book/no-such-file.txt': No such file or directory
....

View file

@ -0,0 +1,44 @@
= The Nix REPL
The Nix REPL footnote:[REPL is an acronym for (Read-Eval-Print-Loop).]
is an interactive environment for evaluating and debugging Nix code.
It's also a good place to begin learning Nix.
Enter it using the command `nix repl`.
Within the REPL, type `:?` to see a list of available commands.
[source]
....
$# echo "$ nix repl"
Welcome to Nix 2.18.1. Type :? for help.
nix-repl> :?
The following commands are available:
<expr> Evaluate and print expression
<x> = <expr> Bind expression to variable
:a, :add <expr> Add attributes from resulting set to scope
:b <expr> Build a derivation
:bl <expr> Build a derivation, creating GC roots in the
working directory
:e, :edit <expr> Open package or function in $EDITOR
:i <expr> Build derivation, then install result into
current profile
:l, :load <path> Load Nix expression and add it to scope
:lf, :load-flake <ref> Load Nix flake and add it to scope
:p, :print <expr> Evaluate and print expression recursively
:q, :quit Exit nix-repl
:r, :reload Reload all files
:sh <expr> Build dependencies of derivation, then start
nix-shell
:t <expr> Describe result of evaluation
:u <expr> Build derivation, then start nix-shell
:doc <expr> Show documentation of a builtin function
:log <expr> Show logs for a derivation
:te, :trace-enable [bool] Enable, disable or toggle showing traces for
errors
:?, :help Brings up this help menu
....
A command that is useful to beginners is `:t`, which tells you the type of an expression.
Note that the command to exit the REPL is `:q` (or `:quit` if you prefer).

View file

@ -0,0 +1,42 @@
# String operations
String concatenation uses the `+` operator.
[source]
....
nix-repl> "Hello, " + "world!"
"Hello, world!"
....
You can use the `${_variable_}` syntax to insert the value of a variable within a string.
[source]
....
nix-repl> name = "Wombat"
nix-repl> "Hi, I'm ${name}."
"Hi, I'm Wombat."
....
[IMPORTANT]
====
You cannot mix numbers and strings.
Nix does provide functions for converting between types; we'll see these later.
Earlier we set `a = 7`, so the following expression fails.
[source]
....
nix-repl> "My favourite number is ${a}."
error:
… while evaluating a path segment
at «string»:1:25:
1| "My favourite number is ${a}."
| ^
error: cannot coerce an integer to a string
....
====
// TODO Talk about "strings with context" https://shealevy.com/blog/2018/08/05/understanding-nixs-string-context/

View file

@ -0,0 +1,90 @@
= Data types
== Strings
Strings are enclosed by double quotes (`"`), or _two_ single quotes (`'`).
"Hello, world!"
''This string contains "double quotes"''
They can span multiple lines.
''Old pond
A frog jumps in
The sound of water
-- Basho''
== Integers
7
256
== Floating point numbers
3.14
6.022e23
== Boolean
The Boolean values in Nix are `true` and `false`.
== Paths
File paths are play an important role in building software, so Nix has a special data type for them.
Paths may be absolute (e.g. `/bin/sh`) or relative (e.g. `./data/file1.csv`).
Note that paths are not enclosed in quotation marks; they are not strings!
Enclosing a path in angle brackets, e.g. <nixpkgs> causes the directories
listed in the environment variable NIX_PATH to be searched for the given
file or directory name.
These are called _lookup paths_.
== Lists
List elements are enclosed in square brackets and separated by spaces (not commas).
The elements need not be of the same type.
[ "apple" 123 ./build.sh false ]
Lists can be empty.
[]
List elements can be of any type, and can even be lists themselves.
[ [ 1 2 ] [ 3 4 ] ]
== Attribute sets
Attribute sets associate keys with values.
They are enclosed in curly brackets, and the associations are terminated by semi-colons.
Note that the final semi-colon before the closing bracket is required.
{ name = "Professor Paws"; age = 10; species = "cat"; }
Attribute sets can be empty.
{}
Values of attribute sets can be of any type, and can even be attribute sets themselves.
{ name = { first = "Professor"; last = "Paws"; }; age = 10; species = "cat"; }
[NOTE]
====
In some Nix documentation, and in many articles about Nix,
attribute sets are simply called "sets".
====
== Functions
We'll learn how to write functions later in this chapter.
For now, note that functions are "first-class values",
meaning that they can be treated like any other data type.
For example, a function can be assigned to a variable, appear as an element in a list,
or be associated with a key in an attribute set.
[ "apple" 123 ./build.sh false (x: x*x) ]
{ name = "Professor Paws"; age = 10; species = "cat"; formula = (x: x*2); }

View file

@ -0,0 +1,33 @@
= Variables
You can declare variables in Nix and assign values to them.
// TODO explain that values are immutable.
[source]
....
nix-repl> a = 7
nix-repl> b = 3
nix-repl> a - b
4
....
[IMPORTANT]
====
As mentioned previously, omitting the spaces around operators can have unexpected results.
As Nix allows hyphens (`-`) in variable names,
`a-b` is interpreted as the name of a variable in the following example.
[source]
....
nix-repl> a-b
error: undefined variable 'a-b'
at «string»:1:1:
1| a-b
| ^
....
====