diff --git a/doc/manual/src/language/operators.md b/doc/manual/src/language/operators.md
index 32398189d..797f13bd3 100644
--- a/doc/manual/src/language/operators.md
+++ b/doc/manual/src/language/operators.md
@@ -1,28 +1,167 @@
# Operators
-The table below lists the operators in the Nix language, in
-order of precedence (from strongest to weakest binding).
+| Name | Syntax | Associativity | Precedence |
+|----------------------------------------|--------------------------------------------|---------------|------------|
+| [Attribute selection] | *attrset* `.` *attrpath* \[ `or` *expr* \] | none | 1 |
+| Function application | *func* *expr* | left | 2 |
+| [Arithmetic negation][arithmetic] | `-` *number* | none | 3 |
+| [Has attribute] | *attrset* `?` *attrpath* | none | 4 |
+| List concatenation | *list* `++` *list* | right | 5 |
+| [Multiplication][arithmetic] | *number* `*` *number* | left | 6 |
+| [Division][arithmetic] | *number* `/` *number* | left | 6 |
+| [Subtraction][arithmetic] | *number* `-` *number* | left | 7 |
+| [Addition][arithmetic] | *number* `+` *number* | left | 7 |
+| [String concatenation] | *string* `+` *string* | left | 7 |
+| [Path concatenation] | *path* `+` *path* | left | 7 |
+| [Path and string concatenation] | *path* `+` *string* | left | 7 |
+| [String and path concatenation] | *string* `+` *path* | left | 7 |
+| Logical negation (`NOT`) | `!` *bool* | none | 8 |
+| [Update] | *attrset* `//` *attrset* | right | 9 |
+| [Less than][Comparison] | *expr* `<` *expr* | none | 10 |
+| [Less than or equal to][Comparison] | *expr* `<=` *expr* | none | 10 |
+| [Greater than][Comparison] | *expr* `>` *expr* | none | 10 |
+| [Greater than or equal to][Comparison] | *expr* `>=` *expr* | none | 10 |
+| [Equality] | *expr* `==` *expr* | none | 11 |
+| Inequality | *expr* `!=` *expr* | none | 11 |
+| Logical conjunction (`AND`) | *bool* `&&` *bool* | left | 12 |
+| Logical disjunction (`OR`) | *bool* `||` *bool* | left | 13 |
+| [Logical implication] | *bool* `->` *bool* | none | 14 |
+
+[string]: ./values.md#type-string
+[path]: ./values.md#type-path
+[number]: ./values.md#type-number
+[list]: ./values.md#list
+[attribute set]: ./values.md#attribute-set
+
+## Attribute selection
+
+Select the attribute denoted by attribute path *attrpath* from [attribute set] *attrset*.
+If the attribute doesn’t exist, return *value* if provided, otherwise abort evaluation.
+
+
+
+An attribute path is a dot-separated list of attribute names.
+An attribute name can be an identifier or a string.
+
+> *attrpath* = *name* [ `.` *name* ]...
+> *name* = *identifier* | *string*
+> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
+
+[Attribute selection]: #attribute-selection
+
+## Has attribute
+
+> *attrset* `?` *attrpath*
+
+Test whether [attribute set] *attrset* contains the attribute denoted by *attrpath*.
+The result is a [Boolean] value.
+
+[Boolean]: ./values.md#type-boolean
+
+[Has attribute]: #has-attribute
+
+## Arithmetic
+
+Numbers are type-compatible:
+Pure integer operations will always return integers, whereas any operation involving at least one floating point number return a floating point number.
+
+See also [Comparison] and [Equality].
+
+The `+` operator is overloaded to also work on strings and paths.
+
+[arithmetic]: #arithmetic
+
+## String concatenation
+
+> *string* `+` *string*
+
+Concatenate two [string]s and merge their string contexts.
+
+[String concatenation]: #string-concatenation
+
+## Path concatenation
+
+> *path* `+` *path*
+
+Concatenate two [path]s.
+The result is a path.
+
+[Path concatenation]: #path-concatenation
+
+## Path and string concatenation
+
+> *path* + *string*
+
+Concatenate *[path]* with *[string]*.
+The result is a path.
+
+> **Note**
+>
+> The string must not have a string context that refers to a [store path].
+
+[Path and string concatenation]: #path-and-string-concatenation
+
+## String and path concatenation
+
+> *string* + *path*
+
+Concatenate *[string]* with *[path]*.
+The result is a string.
+
+> **Important**
+>
+> The file or directory at *path* must exist and is copied to the [store].
+> The path appears in the result as the corresponding [store path].
+
+[store path]: ../glossary.md#gloss-store-path
+[store]: ../glossary.md#gloss-store
+
+[Path and string concatenation]: #path-and-string-concatenation
+
+## Update
+
+> *attrset1* + *attrset2*
+
+Update [attribute set] *attrset1* with names and values from *attrset2*.
+
+The returned attribute set will have of all the attributes in *e1* and *e2*.
+If an attribute name is present in both, the attribute value from the former is taken.
+
+[Update]: #update
+
+## Comparison
+
+Comparison is
+
+- [arithmetic] for [number]s
+- lexicographic for [string]s and [path]s
+- item-wise lexicographic for [list]s:
+ elements at the same index in both lists are compared according to their type and skipped if they are equal.
+
+All comparison operators are implemented in terms of `<`, and the following equivalencies hold:
+
+| comparison | implementation |
+|--------------|-----------------------|
+| *a* `<=` *b* | `! (` *b* `<` *a* `)` |
+| *a* `>` *b* | *b* `<` *a* |
+| *a* `>=` *b* | `! (` *a* `<` *b* `)` |
+
+[Comparison]: #comparison-operators
+
+## Equality
+
+- [Attribute sets][attribute set] and [list]s are compared recursively, and therefore are fully evaluated.
+- Comparison of [function]s always returns `false`.
+- Numbers are type-compatible, see [arithmetic] operators.
+- Floating point numbers only differ up to a limited precision.
+
+[function]: ./constructs.md#functions
+
+[Equality]: #equality
+
+## Logical implication
+
+Equivalent to `!`*b1* `||` *b2*.
+
+[Logical implication]: #logical-implication
-| Name | Syntax | Associativity | Description | Precedence |
-| ------------------------ | ----------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
-| Select | *e* `.` *attrpath* \[ `or` *def* \] | none | Select attribute denoted by the attribute path *attrpath* from set *e*. (An attribute path is a dot-separated list of attribute names.) If the attribute doesn’t exist, return *def* if provided, otherwise abort evaluation. | 1 |
-| Application | *e1* *e2* | left | Call function *e1* with argument *e2*. | 2 |
-| Arithmetic Negation | `-` *e* | none | Arithmetic negation. | 3 |
-| Has Attribute | *e* `?` *attrpath* | none | Test whether set *e* contains the attribute denoted by *attrpath*; return `true` or `false`. | 4 |
-| List Concatenation | *e1* `++` *e2* | right | List concatenation. | 5 |
-| Multiplication | *e1* `*` *e2*, | left | Arithmetic multiplication. | 6 |
-| Division | *e1* `/` *e2* | left | Arithmetic division. | 6 |
-| Addition | *e1* `+` *e2* | left | Arithmetic addition. | 7 |
-| Subtraction | *e1* `-` *e2* | left | Arithmetic subtraction. | 7 |
-| String Concatenation | *string1* `+` *string2* | left | String concatenation. | 7 |
-| Not | `!` *e* | none | Boolean negation. | 8 |
-| Update | *e1* `//` *e2* | right | Return a set consisting of the attributes in *e1* and *e2* (with the latter taking precedence over the former in case of equally named attributes). | 9 |
-| Less Than | *e1* `<` *e2*, | none | Arithmetic/lexicographic comparison. | 10 |
-| Less Than or Equal To | *e1* `<=` *e2* | none | Arithmetic/lexicographic comparison. | 10 |
-| Greater Than | *e1* `>` *e2* | none | Arithmetic/lexicographic comparison. | 10 |
-| Greater Than or Equal To | *e1* `>=` *e2* | none | Arithmetic/lexicographic comparison. | 10 |
-| Equality | *e1* `==` *e2* | none | Equality. | 11 |
-| Inequality | *e1* `!=` *e2* | none | Inequality. | 11 |
-| Logical AND | *e1* `&&` *e2* | left | Logical AND. | 12 |
-| Logical OR | *e1* ||
*e2* | left | Logical OR. | 13 |
-| Logical Implication | *e1* `->` *e2* | none | Logical implication (equivalent to !e1 || e2
). | 14 |
diff --git a/doc/manual/src/language/values.md b/doc/manual/src/language/values.md
index 08baa8f95..3973518ca 100644
--- a/doc/manual/src/language/values.md
+++ b/doc/manual/src/language/values.md
@@ -85,9 +85,10 @@
Numbers, which can be *integers* (like `123`) or *floating point*
(like `123.43` or `.27e13`).
- Numbers are type-compatible: pure integer operations will always
- return integers, whereas any operation involving at least one
- floating point number will have a floating point number as a result.
+ See [arithmetic] and [comparison] operators for semantics.
+
+ [arithmetic]: ./operators.md#arithmetic
+ [comparison]: ./operators.md#comparison
- Path