Repository: tweag/nickel
Pull request #796 (2022-08-05 16:01:23)

Fix sort benchmark and stdlib function
The sort benchmark was crashing because of a contraction violation. It still used ``` `Less``` instead of ``` `Lesser``` after it was renamed.  Though `array.sort`'s implementation itself still used ``` `Less```.

I took the opportunity to make the sort benchmark depend on the input, using some questionable random number generation methods.

I also added a test for `array.sort` so this kind of thing doesn't happen in the future.


Patch:
diff --git a/.markdownlint.json b/.markdownlint.json
deleted file mode 100644
index 840bd891..00000000
--- a/.markdownlint.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "default": true,
-    "MD013": {
-        "code_blocks": false,
-        "tables": false
-    },
-    "MD024": {
-        "allow_different_nesting": true
-    }
-}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 78f39916..0ccb4842 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -94,3 +94,4 @@ aspects to consider when working on Nickel:
 [tweag]: https://www.tweag.io
 [rfcs]: ./rfcs/
 [matrix-nickel]: https://matrix.to/#/#nickel-lang:matrix.org
+[nickel-lang.org]: https://nickel-lang.org
diff --git a/Cargo.toml b/Cargo.toml
index ef88c677..f0617a68 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,7 +8,7 @@ description = "Programmable configuration files."
 homepage = "https://nickel-lang.org"
 repository = "https://github.com/tweag/nickel"
 keywords = ["configuration", "language", "nix"]
-edition = "2021"
+edition = "2018"
 
 [[bin]]
 name = "nickel"
diff --git a/HACKING.md b/HACKING.md
index d013fc82..a1224d07 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -1,4 +1,5 @@
-# The Nickel developer guide
+The Nickel developer guide
+==========================
 
 There are two ways to set up a development environment for Nickel: using
 [Nix][nix], or directly via your preferred system package manager. Nix is able
@@ -11,14 +12,12 @@ itself_. The reason is that incremental compilation for Rust and Nix is not
 there yet, and incremental rebuilds using only Nix are going to be painfully
 long.
 
-## Content
+# Content
 
 The Nickel repository consist in 3 crates:
 
-- `nickel-lang` (path: `.`). The main crate containing the interpreter as a
-  library as well as the `nickel` binary.
-- `nickel-lang-lsp` (path: `lsp/nls/`). the Nickel Language Server (NLS), an LSP
-  server for Nickel.
+- `nickel-lang` (path: `.`). The main crate containing the interpreter as a library as well as the `nickel` binary.
+- `nickel-lang-lsp` (path: `lsp/nls/`). the Nickel Language Server (NLS), an LSP server for Nickel.
 - `nickel-lang-utilities`: (path: `utilities/`). An auxiliary crate regrouping
    helpers for tests and benchmarks. Not required to build `nickel` itself.
 
@@ -27,9 +26,9 @@ Other noteworthy items:
 - The user manual in `doc/manual/`, as a bunch of markdown files.
 - A VSCode extension for NLS in `lsp/client-extension/`.
 
-## Setup a development environment
+# Setup a development environment
 
-### Using Nix
+## Using Nix
 
 To set up a development environment using a recent Nix (>= 2.4):
 
@@ -38,12 +37,12 @@ To set up a development environment using a recent Nix (>= 2.4):
    in a shell with all the required tool to hack on Nickel (`rust`, `cargo`,
    etc.)
 
-### Without Nix
+## Without Nix
 
 Otherwise, you can install the Rust toolchain separately: follow the
 instructions of the [Rust installation guide][install-rust].
 
-## Building
+# Building
 
 You can build all crates at once:
 
@@ -55,7 +54,7 @@ $ ./target/debug/nls --version
 nickel-lang-lsp 0.1.0
 ```
 
-### Nickel
+## Nickel
 
 To only build the main crate `nickel-lang`, run:
 
@@ -65,7 +64,7 @@ $ ./target/debug/nickel --version
 nickel-lang 0.1.0
 ```
 
-### NLS (nickel-lang-lsp)
+## NLS (nickel-lang-lsp)
 
 To build NLS separately, the LSP server for Nickel, build the `nickel-lang-lsp` crate:
 
@@ -77,7 +76,7 @@ nickel-lang-lsp 0.1.0
 
 (Alternatively, you can run `cargo build` directly inside `lsp/nls/`).
 
-### WebAssembly REPL
+## WebAssembly REPL
 
 There is a WebAssembly (WASM) version of the REPL, which is used for the online
 playground on [nickel-lang.org][nickel-lang.org]. To ease the build, we use the
@@ -89,7 +88,7 @@ compilation is not as good as with direct usage of `cargo`.
 
 Both methods are described below.
 
-#### Using Nix
+### Using Nix
 
 At the root of the repository:
 
@@ -99,7 +98,7 @@ $ ls result/nickel-repl
 LICENSE  package.json nickel_lang_bg.js  nickel_lang_bg.wasm [..]
 ```
 
-#### Using Cargo
+### Using Cargo
 
 1. [Install `wasm-pack`][install-wasm-pack]
 2. Run `wasm-pack` on the `nickel-repl` crate:
@@ -112,7 +111,7 @@ LICENSE  package.json nickel_lang_bg.js  nickel_lang_bg.wasm [..]
    A `pkg` directory, containing the corresponding NPM package, should now be
    available.
 
-## Testing
+# Testing
 
 Tests are run via `cargo test`. They are two types of tests:
 
@@ -148,7 +147,7 @@ fn non_mergeable() {
 }
 ```
 
-## Benchmarking
+# Benchmarking
 
 If your change is likely to impact performance, it is recommended to run the
 benchmark suite on master and on your branch to assess any performance changes.
@@ -157,7 +156,7 @@ Please report your findings in the description of the PR.
 The benchmark suite is located in the `benches/` directory. To run it:
 
 ```shell
-cargo bench
+$ cargo bench
 ```
 
 Note that a full run takes some time, up to a dozen of minutes. You can run
diff --git a/README.md b/README.md
index feda7034..700e0d28 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,6 @@ configuration, be it for a single app, a machine, whole infrastructure, or a
 build system.
 
 The motivating use cases are in particular:
-
 - The [Nix package manager](https://nixos.org/): Nix is a declarative package
     manager using its own language for specifying packages. Nickel is an
     evolution of the Nix language, while trying to overcome some of its
@@ -67,7 +66,7 @@ The motivating use cases are in particular:
     a specification of the dependency graph.
 
 Most aforementioned projects have their own bespoke configuration language. See
-[Related projects and inspirations](#related-projects-and-inspirations). In
+[Related projects and inspirations](#Related-projects-and-inspirations). In
 general, application-specific languages might suffer from feature creep, lack of
 abstractions or just feel ad hoc. Nickel buys you more for less.
 
@@ -82,46 +81,39 @@ the `nickel-lang` crate documentation).
 ### Run
 
 1. Start Nickel
-
-   - with [flake-enabled](https://nixos.wiki/wiki/Flakes) Nix directly
+   * with [flake-enabled](https://nixos.wiki/wiki/Flakes) Nix directly
      with `nix run nickel` (which pulls it from the global flakes
      registry), or with `nix run github:tweag/nickel` (which pulls it
      from the repo). You can use [our binary cache](https://nickel.cachix.org) to
      prevent rebuilding a lot of packages. You pass in arguments with
      an extra `--` as in `nix run nickel -- repl`,
-   - with `./nickel`, after [building](#build) this repo, depending on the
+   * with `./nickel`, after [building](#Build) this repo, depending on the
      location of the executable and passing in arguments directly,
-   - or with `cargo run` after [building](#build), passing in arguments with
+   * or with `cargo run` after [building](#Build), passing in arguments with
      an extra `--` as in `cargo run -- -f program.ncl`.
 
 2. Run your first program:
-
-    ```console
-    $ ./nickel <<< 'let x = 2 in x + x'
-    4
-    ```
-
-    Or load it from a file:
-
-    ```console
-    $ echo 'let s = "world" in "Hello, " ++ s' > program.ncl
-    $ ./nickel -f program.ncl
-    "Hello, world"
-    ```
-
+  ```console
+  $ ./nickel <<< 'let x = 2 in x + x'
+  4
+  ```
+  Or load it from a file:
+  ```console
+  $ echo 'let s = "world" in "Hello, " ++ s' > program.ncl
+  $ ./nickel -f program.ncl
+  "Hello, world"
+  ```
 3. Start a REPL:
+  ```console
+  $ ./nickel repl
+  nickel> let x = 2 in x + x
+  4
 
-    ```console
-    $ ./nickel repl
-    nickel> let x = 2 in x + x
-    4
-
-    nickel>
-    ```
+  nickel>
+  ```
+  Use `:help` for a list of available commands.
 
-    Use `:help` for a list of available commands.
 4. Export your configuration to JSON, YAML or TOML:
-
   ```console
   $ ./nickel export --format json <<< '{foo = "Hello, world!"}'
   {
@@ -134,46 +126,38 @@ for help about a specific subcommand.
 
 #### Editor Setup
 
-Nickel has syntax highlighting plugins for Vim/Neovim, and VSCode. In-editor
-diagnostics, type hints, and auto-completion are provided by the Nickel Language
-Server. Please follow
-[this guide](https://github.com/tweag/nickel/tree/master/lsp) to setup syntax
-highlighting and NLS.
+Nickel has syntax highlighting plugins for Vim/Neovim, and VSCode.
+In-editor diagnostics, type hints, and auto-completion are provided by the Nickel Language Server.
+Please follow [this guide](https://github.com/tweag/nickel/tree/master/lsp) to setup syntax highlighting and NLS.
 
 ### Build
 
 [rust-guide]: https://doc.rust-lang.org/cargo/getting-started/installation.html
 
 1. Download build dependencies:
-
    - **With Nix**: If you have [Nix](https://nixos.org/nix) installed:
-
      ```console
-     nix-shell shell.nix
+     $ nix-shell shell.nix
      ```
-
      to be dropped in a shell, ready to build. You can use [our binary
-     cache](https://nickel.cachix.org) to prevent rebuilding a lot of packages.
+     cache](https://nickel.cachix.org) to prevent rebuilding a lot of
+     packages.
    - **Without Nix**: otherwise, follow [this guide][rust-guide] to install Rust
      and Cargo first.
-
 1. Build Nickel:
-
    ```console
-   cargo build
+   $ cargo build
    ```
-
    And voilà! Generated files are placed in `target/debug`.
 1. *(optional)* make a symbolic link to the executable:
-
   ```console
-  ln -S nickel target/debug/nickel
+  $ ln -S nickel target/debug/nickel
   ```
 
 ### Tests
 
 ```console
-cargo test
+$ cargo test
 ```
 
 ### Documentation
@@ -185,11 +169,9 @@ repository as a collection of Markdown files in `doc/manual`.
 To get the documentation of the `nickel-lang` codebase itself:
 
 1. Build the doc:
-
-    ```console
-    cargo doc --no-deps
-    ```
-
+  ```console
+  $ cargo doc --no-deps
+  ```
 2. Open the file `target/doc/nickel/index.html` in your browser.
 
 ### Examples
diff --git a/benches/arrays.rs b/benches/arrays.rs
index 4427688c..f4d14a9e 100644
--- a/benches/arrays.rs
+++ b/benches/arrays.rs
@@ -1,6 +1,29 @@
 use criterion::{criterion_main, Criterion};
+use nickel_lang::term::{ArrayAttrs, RichTerm, Term};
 use nickel_lang_utilities::{ncl_bench_group, EvalMode};
 use pprof::criterion::{Output, PProfProfiler};
+use pretty::{BoxAllocator, DocBuilder, Pretty};
+
+/// Generates a pseaudo-random Nickel array as a string.
+fn ncl_random_array(len: usize) -> String {
+    let m = 2_u64.pow(32);
+    let a = 1664525;
+    let c = 1013904223;
+
+    let mut numbers = Vec::with_capacity(len);
+    let mut acc = 1337;
+
+    for _ in 0..len {
+        acc = (a * acc + c) % m;
+        numbers.push(RichTerm::from(Term::Num(acc as f64)));
+    }
+
+    let xs = RichTerm::from(Term::Array(numbers, ArrayAttrs::default()));
+    let doc: DocBuilder<_, ()> = xs.pretty(&BoxAllocator);
+    let mut out = Vec::new();
+    doc.render(80, &mut out).unwrap();
+    String::from_utf8(out).unwrap()
+}
 
 ncl_bench_group! {
 name = benches;
@@ -108,7 +131,7 @@ config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flam
     }, {
         name = "sort normal",
         path = "arrays/sort",
-        args = (20),
+        args = (ncl_random_array(50)),
     }, {
         name = "sum normal 50",
         path = "arrays/sum",
@@ -127,6 +150,15 @@ config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flam
         path = "arrays/primes",
         args = (30),
         eval_mode = EvalMode::DeepSeq,
+    }, {
+        name = "random normal",
+        path = "arrays/random",
+        args = (50),
+    }, {
+        name = "random deepseq",
+        path = "arrays/random",
+        args = (50),
+        eval_mode = EvalMode::DeepSeq,
     }
 }
 criterion_main!(benches);
diff --git a/benches/arrays/fold.ncl b/benches/arrays/fold.ncl
index ddc13b03..240bcb5c 100644
--- a/benches/arrays/fold.ncl
+++ b/benches/arrays/fold.ncl
@@ -1,34 +1,34 @@
-let letter | Num -> string.CharLiteral = fun n =>
-  string.code "a" + (n % 26)
-  |> string.from_code in
+let letter | string.CharLiteral -> string.CharLiteral = fun n =>
+  string.char_code "a" + (n % 26)
+  |> string.char_from_code in
 
 {
   right = {
     strings = {
       run = fun n =>
-        array.fold (fun x acc => acc ++ x) "" (array.generate (fun n => letter n) n)
+        array.fold (fun x y => x ++ "a") (array.generate n (fun n => letter n))
     },
     nums = {
       run = fun n =>
-        array.fold (fun x acc => x*acc + (x - acc)) 0 (array.generate (fun n => n/2) n)
+        array.fold (fun x y => x*y + (x - y)) (array.generate n (fun n => n/2))
     },
     arrays = {
       run = fun n =>
-        array.fold (fun x acc => acc @ [x]) [] (array.generate (fun n => [n]) n)
+        array.fold (fun x acc => [x] ++ acc) (array.generate n (fun n => [n]))
     },
   },
   left = {
     strings = {
       run = fun n =>
-        array.foldl (fun acc x => acc ++ x) "" (array.generate (fun n => letter n) n)
+        array.foldl (fun x y => x ++ "a") (array.generate n (fun n => letter n))
     },
     nums = {
       run = fun n =>
-        array.foldl (fun acc x => x*acc + (x - acc)) 0 (array.generate (fun n => n/2) n)
+        array.foldl (fun x y => x*y + (x - y)) (array.generate n (fun n => n/2))
     },
     arrays = {
       run = fun n =>
-        array.foldl (fun acc x => acc @ [x]) [] (array.generate (fun n => [n]) n)
+        array.foldl (fun x acc => [x] ++ acc) (array.generate n (fun n => [n]))
     },
   }
 }
diff --git a/benches/arrays/random.ncl b/benches/arrays/random.ncl
new file mode 100644
index 00000000..48a0772e
--- /dev/null
+++ b/benches/arrays/random.ncl
@@ -0,0 +1,22 @@
+let mgc 
+  | doc "A multiplicative congruential pseudorandom number generator (MCG)."
+  = fun params x => (params.a * x + params.c) % params.m in
+
+# NOTE: These parameters are from "Table 7: Good multipliers for MCGs with m = 2^32"
+# of the 2021 paper "Computationally Easy, Spectrally Good Multipliers for
+# Congruential Pseudorandom Number Generators", by Guy Steele and Sebastiano Vigna.
+# But, they cannot be used because they require bit-shifting to select the 32 MSBs.
+# let params = { m = num.pow 2 32, a = 2480367069 } in
+
+# These parameters are from the "Numerical Recipes" book.
+let params = { m = num.pow 2 32, a = 1664525, c = 1013904223 } in
+
+let rec array_random = fun init n =>
+  if n == 0 then [init]
+  else 
+    let next = mgc params init in
+    [next] @ array_random next (n - 1)
+in
+
+{ run = array_random 42 }
+
diff --git a/benches/arrays/sort.ncl b/benches/arrays/sort.ncl
index e0a9f834..3204d762 100644
--- a/benches/arrays/sort.ncl
+++ b/benches/arrays/sort.ncl
@@ -1,5 +1,7 @@
-let nums = [3288, 2438, 1462, 437, 17, 1929, 2595, 2702, 831, 3685, 1906, 420, 2646, 1906, 2539, 184, 299, 3455, 2320, 1471, 1812, 3837, 1000, 2097, 945, 1973, 1090, 2285, 2272, 1045, 848, 3194, 2113, 537, 1953, 561, 2082, 2416, 3182, 3660, 3379, 1458, 39, 2720, 2469, 811, 837, 548, 3021, 2961, 2860, 2092, 942, 2511, 1769, 168, 130, 2755, 2552, 1057, 2619, 1848, 2373, 2012, 2339, 2521, 3593, 2784, 3094, 2260, 1994, 690, 828, 1298, 3434, 2929, 2188, 1285, 3783, 3635, 971, 3334, 87, 1578, 1363, 533, 3634, 1874, 830, 3976, 1140, 789, 1483, 1966, 1626, 3552, 2968, 3301, 749, 2576] in
-let ascending = fun x y => if x < y then `Less else if (x == y) then `Equal else `Greater in
-{
-    run = fun n => array.sort ascending nums
-}
+let ascending = fun x y => 
+  if x < y then `Lesser 
+  else if x == y then `Equal 
+  else `Greater 
+in
+
+{ run = array.sort ascending }
diff --git a/benches/mantis/README.md b/benches/mantis/README.md
index dea8dd66..e24fda82 100644
--- a/benches/mantis/README.md
+++ b/benches/mantis/README.md
@@ -1,17 +1,15 @@
-# Mantis bench
-
 This bench is a copy of [nickel-mantis-ops](https://github.com/tweag/nickel-mantis-ops)
 by @yannham
 
-## Mantis Ops in Nickel
+# Mantis Ops in Nickel
 
 This is a tentative to convert the [mantis ops repo of
 IOHK](https://github.com/input-output-hk/mantis-ops) from CUE to Nickel, as a
 dogfooding exercise. This repo tries to respect the same file hierarchy than the
 original one, whenever possible.
 
-### Example invocation
+## Example invocation
 
-```console
+```
 nickel export <<< 'import "deploy.ncl" {namespace="mantis-staging", job="miner"}'
 ```
diff --git a/benches/mantis/deploy.ncl b/benches/mantis/deploy.ncl
index fd87cca4..c22d2c08 100644
--- a/benches/mantis/deploy.ncl
+++ b/benches/mantis/deploy.ncl
@@ -55,7 +55,7 @@ fun vars =>
     logLevel | default = "INFO",
     loggers = defaultLoggers,
     job = vars.job,
-    role | [| `passive, `miner, `backup |] = vars.role,
+    role | [| passive, miner, backup |] = vars.role,
   } in
 
   let jobDefs = {
diff --git a/build.rs b/build.rs
index 59288b85..ca5c2836 100644
--- a/build.rs
+++ b/build.rs
@@ -1,6 +1,3 @@
 fn main() {
-    lalrpop::Configuration::new()
-        .use_cargo_dir_conventions()
-        .process_file("src/parser/grammar.lalrpop")
-        .unwrap();
+    lalrpop::process_root().unwrap();
 }
diff --git a/doc/manual/contracts.md b/doc/manual/contracts.md
index 162e72ff..40a2069c 100644
--- a/doc/manual/contracts.md
+++ b/doc/manual/contracts.md
@@ -1,7 +1,6 @@
 ---
 slug: contracts
 ---
-
 # Contracts in Nickel
 
 (For the motivation behind contracts and a high-level overview of contracts and
@@ -33,7 +32,7 @@ are performed:
 2. Check that the result is a number.
 3. If it is, return the expression unchanged. Otherwise, raise an error.
 
-```text
+```
 $ nickel repl
 nickel>1 + 1 | Num
 2
@@ -73,8 +72,8 @@ A custom contract is a function of two arguments:
   `contract.blame_with` when the contract isn't satisfied.
 - The value being checked.
 
-Upon success, the contract must return the original value. We will see the
-reason why in the [laziness](#laziness) section. To signal failure, we use
+Upon success, the contract must return the original value. We will see the reason why
+in the [laziness](#laziness) section. To signal failure, we use
 `contract.blame` or its variant `contract.blame_with` that takes an additional
 error message as a parameter. `blame` immediately aborts the execution and
 reports a contract violation error.
@@ -83,7 +82,7 @@ In `IsFoo`, we first test if the value is a string, and then if it is equal to
 `"foo"`, in which case the contract succeeds. Otherwise, the contract fails with
 appropriate error messages. Let us try:
 
-```text
+```
 nickel>1 | IsFoo
 error: contract broken by a value [not a string].
 [..]
@@ -255,7 +254,7 @@ existing contracts seamlessly as building blocks for new contracts.
 
 If we export this example to json, we get:
 
-```console
+```
 $ nickel -f config.ncl export
 error: contract broken by a value.
    ┌─ :1:1
@@ -303,7 +302,7 @@ Additionally to defining the contracts of fields, record contract can also
 attach metadata (see [merging](./merging.md)) to fields, such as a documentation
 or default value:
 
-```text
+```
 nickel>let MyConfig = {
     foo | doc "This documentation will propagate to the final value!"
         | Str
@@ -327,7 +326,7 @@ nickel>:query config.foo
 
 By default, record contracts are closed, meaning that additional fields are forbidden:
 
-```text
+```
 nickel>let Contract = {foo | Str}
 nickel>{foo = "a", bar = 1} | Contract
 error: contract broken by a value [extra field `bar`].
@@ -337,7 +336,7 @@ error: contract broken by a value [extra field `bar`].
 If you want to allow additional fields, append `, ..` after the last field
 definition to define an open contract:
 
-```text
+```
 nickel>let Contract = {foo | Str, ..}
 nickel>{foo = "a", bar = 1} | Contract
 { foo = <contract,value="a">, bar = 1}
@@ -351,7 +350,7 @@ contract or a normal value. If a field is defined both in the contract and the
 checked value, the two definitions will be merged in the final result. For
 example:
 
-```text
+```
 nickel>let Secure = {
   must_be_very_secure | Bool = true,
   data | Str,
@@ -389,7 +388,7 @@ fields: thus, the contract `{bar | Str}` attached to `foo` will actually behave
 as an open contract, even if you didn't use `..`. This is usually not what you
 want:
 
-```text
+```
 nickel>let ContractPipe = {
   sub_field | {foo | Str}
 }
@@ -419,7 +418,7 @@ as contracts. In fact, any type constructor of the
 An array contract checks that the value is an array and applies the parameter
 contract to each element:
 
-```text
+```
 nickel>let VeryBig = contract.from_predicate (fun value =>
   builtin.is_num value
   && value >= 1000)
@@ -475,7 +474,7 @@ have a bug that you need to fix.
 The interpreter automatically performs book-keeping for functions contracts in
 order to make this caller/callee distinction:
 
-```text
+```
 nickel>let add_semi | Str -> Str = fun x => x ++ ";" in
 add_semi 1
 error: contract broken by the caller.
@@ -493,7 +492,7 @@ The beauty of function contracts is that they gracefully scale to higher-order
 functions as well. Higher-order functions are functions that take other
 functions as parameters. Here is an example:
 
-```text
+```
 nickel>let apply_fun | (Num -> Num) -> Num = fun f => f 0 in
 apply_fun (fun x => "a")
 error: contract broken by the caller.
@@ -541,7 +540,7 @@ information on a large configuration without having to actually evaluate
 everything. We will use a dummy failing expression `1 + "a"` to observe where
 evaluation takes place:
 
-```text
+```
 nickel>let config = {fail = 1 + "a", data | doc "Some information" = 42}
 nickel>:query config.data
 * value: 42
@@ -630,7 +629,7 @@ value and continues with the second argument (here, our wrapped `value`).
 
 Let us see if we indeed preserved laziness:
 
-```text
+```
 nickel>let config | NumBoolDict = {
     "1" = 1 + "a", # Same as our previous "fail"
     "0" | doc "Some information" = true,
@@ -643,7 +642,7 @@ nickel>:query config."0"
 Yes! Our contract doesn't unduly cause the evaluation of the field `"1"`. Does
 it check anything, though?
 
-```text
+```
 nickel>let config | NumBoolDict = {
   not_a_number = false,
   "0" | doc "Some information" = false,
diff --git a/doc/manual/cookbook.md b/doc/manual/cookbook.md
index bcd3a46d..02bca2bb 100644
--- a/doc/manual/cookbook.md
+++ b/doc/manual/cookbook.md
@@ -19,8 +19,7 @@ obliterate the types, making your library basically unusable inside typed code.
 ### Example
 
 DON'T
-
-```nickel
+```
 {
   foo :  Num -> Num = fun x => x + 1,
   bar : Num -> Num = foo,
@@ -28,8 +27,7 @@ DON'T
 ```
 
 BUT DO
-
-```nickel
+```
 {
   foo = fun x => x + 1,
   bar = foo,
@@ -43,14 +41,13 @@ Alternatively, you can repeat your types both at the function level and at the
 record level. It makes code more navigable and `query`-friendly, but at the
 expense of repetition and duplicated contract checks. It is also currently
 required for polymorphic functions because of [the following
-bug](https://github.com/tweag/nickel/issues/360).
-
-<!-- # Note: we already have type wildcard, but they don't "export" the inferred type. -->
-<!-- A better solution will probably be implemented in the future: type wildcard (TODO: -->
-<!--  -->
-<!-- ```nickel -->
-<!-- { -->
-<!--   foo : Num -> Num = fun x => x + 1, -->
-<!--   bar : Num -> Num = foo, -->
-<!-- } : _ -->
-<!-- ``` -->
+bug](https://github.com/tweag/nickel/issues/360). A better solution will
+probably be implemented in the future: type holes (TODO: MAY ACTUALLY BE AVAILABLE FOR RELEASE)
+
+(NOT YET POSSIBLE)
+```
+{
+  foo : Num -> Num = fun x => x + 1,
+  bar : Num -> Num = foo,
+} : _
+```
diff --git a/doc/manual/correctness.md b/doc/manual/correctness.md
index 595ad347..f3d03c84 100644
--- a/doc/manual/correctness.md
+++ b/doc/manual/correctness.md
@@ -73,7 +73,7 @@ of properties that can be checked for, such as:
 
 Both types and contracts are enforced in a similar way, using an annotation:
 
-```text
+```
 $ nickel repl
 nickel> 1 + 1.5 : Num
 2.5
@@ -106,7 +106,7 @@ difference between types and contracts in practice.
 Say we need a function to convert an array of key-value pairs to an array of keys
 and an array of values. Let's call it `split`:
 
-```text
+```
 nickel> split [{key = "foo", value = 1}, {key = "bar", value = 2}]
 {keys = ["foo", "bar"], values = [1, 2]}
 
@@ -146,10 +146,9 @@ split [{key = "foo", value = 1}, {key = "bar", value = 2}]
 
 We want to ensure that the callers to `split` pass an array
 verifying:
-
-- elements are records with a `key` field and a `value` field
-- keys are strings
-- values can be anything, but must all have the same type
+ - elements are records with a `key` field and a `value` field
+ - keys are strings
+ - values can be anything, but must all have the same type
 
 We also want to make sure our implementation correctly returns a value which is
 a record with a field `keys` that is an array of strings, and a field `values`
@@ -190,20 +189,18 @@ function contract for `split` has the following limitations:
   potentially back into unhelpful dynamic type errors. Evaluating `config.ncl`
   indeed reports the following error:
 
-     ```text
-     error: Type error
-       ┌─ repl-input-12:6:27
-       │
-     6 │         keys = acc.keys @ pair.key,
-       │                           ^^^^^^^^ This expression has type Str, but Array was expected
-       │
-       ┌─ repl-input-13:1:45
-       │
-     1 │ lib.split [{key = "foo", value = 1}, {key = "bar", value = 2}]
-       │                                             ----- evaluated to this
-       │
-       = @, 2nd operand
-     ```
+        error: Type error
+        ┌─ repl-input-12:6:27
+        │
+      6 │         keys = acc.keys @ pair.key,
+        │                           ^^^^^^^^ This expression has type Str, but Array was expected
+        │
+        ┌─ repl-input-13:1:45
+        │
+      1 │ lib.split [{key = "foo", value = 1}, {key = "bar", value = 2}]
+        │                                             ----- evaluated to this
+        │
+        = @, 2nd operand
 
   This error is not very helpful to the caller. It points to inside the
   implementation of `split`, and to the `key = "bar"` part of the argument,
@@ -226,7 +223,7 @@ correctly reported.
 What's more, intermediate values are also typechecked. Evaluating or just
 typechecking `lib.ncl` already reports an error:
 
-```text
+```
 error: Incompatible rows declaration
   ┌─ repl-input-14:9:7
   │
@@ -288,7 +285,7 @@ let level = 1 in
 
 We get:
 
-```text
+```
 error: incompatible types
   ┌─ repl-input-0:3:26
   │
@@ -320,7 +317,7 @@ let level = 4 in
 
 This correctly reports an error, and even gives the computed offending value:
 
-```text
+```
 error: contract broken by a value.
   ┌─ :1:1
   │
diff --git a/doc/manual/introduction.md b/doc/manual/introduction.md
index 10e53333..96d30bd7 100644
--- a/doc/manual/introduction.md
+++ b/doc/manual/introduction.md
@@ -52,7 +52,6 @@ configuration, be it for a single app, a machine, whole infrastructure, or a
 build system.
 
 The motivating use cases are in particular:
-
 - The [Nix package manager](https://nixos.org/): Nix is a declarative package
     manager using its own language for specifying packages. Nickel is an
     evolution of the Nix language, while trying to overcome some of its
diff --git a/doc/manual/merging.md b/doc/manual/merging.md
index 125f0e52..91d22ddc 100644
--- a/doc/manual/merging.md
+++ b/doc/manual/merging.md
@@ -31,9 +31,9 @@ following situations:
 - [Merging two records without common fields](#simple-merge-(no-common-fields))
 - [Merging records with common fields](#recursive-merge-(with-common-fields))
 - [Merging records with metadata](#merging-record-with-metadata)
-  - [Default values](#default-values)
-  - [Contracts](#contracts)
-  - [Documentation](#documentation)
+  * [Default values](#default-values)
+  * [Contracts](#contracts)
+  * [Documentation](#documentation)
 - [Recursive overriding](#recursive-overriding)
 
 ## Simple merge (no common fields)
@@ -46,7 +46,7 @@ to `{foo = 1, bar = "bar", baz = false}`.
 
 Technically, if we write the left operand as:
 
-```text
+```
 left = {
   field_left_1 = value_left_1,
   ..,
@@ -56,7 +56,7 @@ left = {
 
 And the right operand as:
 
-```text
+```
 right {
   field_right_1 = value_right_1,
   ..,
@@ -66,7 +66,7 @@ right {
 
 Then the merge `left & right` evaluates to the record:
 
-```text
+```
 {
   field_left_1 = value_left_1,
   ..,
@@ -161,7 +161,7 @@ unless one of the following condition hold:
 
 ### Specification
 
-```text
+```
 left = {
   field_left_1 = value_left_1,
   ..,
@@ -174,7 +174,7 @@ left = {
 
 And the right operand as:
 
-```text
+```
 right {
   field_right_1 = value_right_1,
   ..,
@@ -188,7 +188,7 @@ right {
 Where the `field_left_i` and `field_right_j` are distinct for all `i` and `j`.
 Then the merge `left & right` evaluates to the record:
 
-```text
+```
 {
   field_left_1 = value_left_1,
   ..,
@@ -204,7 +204,7 @@ Then the merge `left & right` evaluates to the record:
 
 For two values `v1` and `v2`, if at least one value is not a record, then
 
-```text
+```
 v1 & v2 = v1    if (type_of(v1) is Num, Bool, Str, Enum or v1 == null)
                    AND v1 == v2
           _|_   otherwise (indicates failure)
@@ -271,7 +271,7 @@ recursively merged, if the priorities are the same. Without loss of generality,
 we consider the simple case of two records with only one field, which is the
 same on both side:
 
-```text
+```
 {common = left} & {common = right}
 = {
   common = left          if p(left) > p(right)
@@ -308,7 +308,7 @@ Because merging is meant to be symmetric, Nickel is unable to know which value
 to pick between `enabled = true` and `enabled = false` for the firewall, and
 thus fail:
 
-```text
+```
 error: non mergeable terms
   ┌─ repl-input-0:2:22
   │
@@ -426,7 +426,7 @@ let GreaterThan
 
 This fails at evaluation:
 
-```text
+```
 error: contract broken by a value.
 [..]
    ┌─ repl-input-1:16:19
@@ -441,6 +441,7 @@ note:
    │            ^^^^^^^^^^^^^^^^ bound here
 ```
 
+
 ### Documentation
 
 Documentation is attached via the `doc` keyword. Documentation is propagated
@@ -457,10 +458,9 @@ config.ncl query foo` on:
 }
 ```
 
-Will print `"Some documentation"` as expected. If both sides have documentation,
-the behavior is unspecified, as merging two distinct blobs of text doesn't make
-sense in general. Currently, Nickel will randomly keeps one of the two in
-practice.
+Will print `"Some documentation"` as expected. If both sides have documentation, the behavior
+is unspecified, as merging two distinct blobs of text doesn't make sense
+in general. Currently, Nickel will randomly keeps one of the two in practice.
 
 ## Recursive overriding
 
@@ -500,9 +500,8 @@ here, `input` -- will also be updated automatically*. For example, `base_config
 }
 ```
 
-Currently, one can only override a field that has been marked as default
-beforehand. A more ergonomic way of overriding is planned, and described in
-[RFC001][rfc001].
+Currently, one can only override a field that has been marked as default beforehand. A
+more ergonomic way of overriding is planned, and described in [RFC001][rfc001].
 
 ### Example
 
diff --git a/doc/manual/syntax.md b/doc/manual/syntax.md
index 9c2b9200..7a44bc4c 100644
--- a/doc/manual/syntax.md
+++ b/doc/manual/syntax.md
@@ -6,24 +6,20 @@ slug: syntax
 
 ## Identifiers
 
-Nickel identifiers start with an alphabetic character, followed by zero or more
-alphanumeric characters, `_` (underscores) or `'` (single quotes). For example,
-`this-isn't-invalid` is a valid identifier.
+Nickel identifiers start with an alphabetic character, followed by zero or more alphanumeric characters, `_` (underscores) or `'` (single quotes). For example, `this-isn't-invalid` is a valid identifier.
 
 ## Simple values
 
 There are four basic kind of values in Nickel :
-
-1. numeric values
-2. boolean values
-3. strings
-4. enum tags
+ 1. numeric values
+ 2. boolean values
+ 3. strings
+ 4. enum tags
 
 ### Numeric values
 
-Nickel has a support for numbers, positive and negative, with or without
-decimals. Internally, those numbers are stored as 64-bits floating point
-numbers, following the IEEE 754 standard.
+Nickel has a support for numbers, positive and negative, with or without decimals.
+Internally, those numbers are stored as 64-bits floating point numbers, following the IEEE 754 standard.
 
 Examples:
 
@@ -44,9 +40,9 @@ There are a some predefined operators for working with numbers :
 | /        | The division operator                                | `1 / 2 = 0.5` |
 | %        | The modulo operator (returns the *signed* remainder) | `5 % 3 = 2`   |
 
-> **Remark about the `-` operator:** Since `-` can be used inside an identifier,
-> the subtraction operators **needs** to be surrounded by spaces: write `a - b`,
-> not `a-b`. `1-2` works as expected, because `1` and `2` aren't identifiers.
+> **Remark about the `-` operator:**
+> Since `-` can be used inside an identifier, the subtraction operators **needs** to be surrounded by spaces:
+> write `a - b`, not `a-b`. `1-2` works as expected, because `1` and `2` are no identifiers.
 
 Numbers can be compared using the following operators :
 | Operator | Description      | Example   |
@@ -72,14 +68,11 @@ In the table below, you will find the operators sorted from highest to lowest pr
 
 The boolean values in Nickel are denoted `true` and `false`.
 
-Nickel features the classical boolean operators *AND* (&&), *OR* (||) and *NOT*
-(!). The *AND* and *OR* operators are lazy in the evaluation of the second
-argument: for example, in `exp1 && exp2`, `exp2` is only evaluated if `exp1`
-evaluates to `false`.
+Nickel features the classical boolean operators *AND* (&&), *OR* (||) and *NOT* (!).
+The _AND_ and _OR_ operators are lazy in the evaluation of the second argument: for example, in `exp1 && exp2`, `exp2` is only evaluated if `exp1` evaluates to `false`.
 
 Examples:
-
-```text
+```
 > true && false
 false
 
@@ -92,17 +85,15 @@ false
 
 ### Strings
 
-Nickel can work with sequences of characters, or strings. Strings are enclosed
-by `" ... "` for a single line string or by `m%" ... "%m` for a multiline
-string. They can be concatenated with the operator `++`. Strings must be UTF-8
-valid.
+Nickel can work with sequences of characters, or strings.
+Strings are enclosed by `" ... "` for a single line string or by `m%" ... "%m` for a multiline string.
+They can be concatenated with the operator `++`.
+Strings must be UTF-8 valid.
 
-The string interpolation syntax is
-`"%{ < expression that evaluates to a string > }"`.
+The string interpolation syntax is `"%{ < expression that evaluates to a string > }"`.
 
 Examples:
-
-```text
+```
 > "Hello, World!"
 "Hello, World!"
 
@@ -124,13 +115,10 @@ error: Type error
 "The number 5."
 ```
 
-Multiline strings are useful to write indented lines. The indentation is
-stripped from the beginning of the first line, and first and last lines are
-ignored if they are empty or contain only spaces.
+Multiline strings are useful to write indented lines. The indentation is stripped from the beginning of the first line, and first and last lines are ignored if they are empty or contain only spaces.
 
 Example:
-
-```text
+```
 > m%"
 This line has no indentation.
   This line is indented.
@@ -146,8 +134,7 @@ This line has no more indentation."
 The only special sequence in a multiline string is the string interpolation.
 
 Examples:
-
-```text
+```
 > m%"Multiline\nString?"%m
 "Multiline\nString?"
 
@@ -156,13 +143,10 @@ Examples:
 String"
 ```
 
-A multiline string can be introduced and closed by multiple `%` signs, as long
-as this amount is equal. If you want to use string interpolation, you must use
-the same amount of `%` as in the delimiters.
+A multiline string can be introduced and closed by multiple `%` signs, as long as this amount is equal. If you want to use string interpolation, you must use the same amount of `%` as in the delimiters.
 
 Examples:
-
-```text
+```
 > m%%"Hello World"%%m
 "Hello World"
 
@@ -176,10 +160,9 @@ Examples:
 "Hello World"
 ```
 
-Multiline strings are "indentation-aware". This means that one could use an
-indented string interpolation and the indentation would behave as expected:
+Multiline strings are "indentation-aware". This means that one could use an indented string interpolation and the indentation would behave as expected:
 
-```text
+```
 > let log = m%"
 if log:
   print("log:", s)
@@ -202,8 +185,8 @@ def concat(str_array, log=false):
 
 #### Enum tags
 
-Enumeration tags are used to express finite alternatives. They are formed by
-writing a backtick `` ` `` followed by any valid identifier. For example,
+Enumeration tags are used to express finite alternatives. They are formed
+by writing a backtick `` ` `` followed by any valid identifier. For example,
 `builtin.serialize` takes an export format as a first argument, which is an enum
 tag among `` `Json ``, `` `Toml `` or `` `Yaml `` (as of version 0.1):
 
@@ -237,12 +220,10 @@ enforce that only valid tags are passed to a function within a typed block. See
 
 ## Equality
 
-Operators `==` and `!=` are used to compare values. Two values of different
-types are never equal: that is, `==` doesn't perform implicit conversions.
+Operators `==` and `!=` are used to compare values. Two values of different types are never equal: that is, `==` doesn't perform implicit conversions.
 
 Examples:
-
-```text
+```
 > 1 == 1
 true
 
@@ -262,15 +243,13 @@ false
 false
 ```
 
+
 ## Composite values
 
 ### Array
-
-An array is a sequence of values. They are delimited by `[` and `]`, and
-elements are separated with `,`.
+An array is a sequence of values. They are delimited by `[` and `]`, and elements are separated with `,`.
 
 Examples:
-
 ```nickel
 [1, 2, 3]
 ["Hello", "World"]
@@ -279,24 +258,20 @@ Examples:
 ```
 
 Arrays can be concatenated with the operator `@`:
-
-```text
+```
 > [1] @ [2, 3]
 [ 1, 2, 3 ]
 ```
 
 ### Record
-
-Records are key-value storage, or in Nickel terms, field-value storage. They are
-delimited by `{` and `}`, and elements are separated with `,`. Field-value
-elements are noted as `field = value`. The fields are strings, but can be
-written without quotes `"` if they respect identifiers syntax. Values can be of
-any type. Elements inside a record are unordered. Two records can be *merged*
-together using the operator `&`. The reader can find more information about
-merging in the [section on merging](./merging.md).
+Records are key-value storage, or in Nickel terms, field-value storage. They are delimited by `{` and `}`, and elements are separated with `,`.
+Field-value elements are noted as `field = value`.
+The fields are strings, but can be written without quotes `"` if they respect identifiers syntax. Values can be of any type.
+Elements inside a record are unordered.
+Two records can be _merged_ together using the operator `&`. The reader can find
+more information about merging in the [section on merging](./merging.md).
 
 Examples:
-
 ```nickel
 {}
 {a = 3}
@@ -305,8 +280,7 @@ Examples:
 ```
 
 Accessing a record field can be done using the `.` operator :
-
-```text
+```
 > { a = 1, b = 5 }.a
 1
 
@@ -317,10 +291,8 @@ error: Missing field
 "one"
 ```
 
-It is possible to write records of records via the *piecewise syntax*, where we
-separate fields by dots:
-
-```text
+It is possible to write records of records via the *piecewise syntax*, where we separate fields by dots:
+```
 > { a = { b = 1 } }
 { a = { b = 1 } }
 
@@ -331,10 +303,8 @@ separate fields by dots:
 { a = { b = 1, c = 2 }, b = 3 }
 ```
 
-When fields are enclosed with double quotes (`"`), you can use string
-interpolation to create or access fields:
-
-```text
+When fields are enclosed with double quotes (`"`), you can use string interpolation to create or access fields:
+```
 > let k = "a" in { "%{k}" = 1 }
 { a = 1 }
 
@@ -345,13 +315,10 @@ interpolation to create or access fields:
 ## Constructs
 
 ### If-Then-Else
-
-This construct allows conditional branching in your code. You can use it as
-`if <bool expr> then <expr> else <expr>`.
+This construct allows conditional branching in your code. You can use it as `if <bool expr> then <expr> else <expr>`.
 
 Examples:
-
-```text
+```
 > if true then "TRUE :)" else "false :("
 "TRUE :)"
 
@@ -366,15 +333,11 @@ Examples:
 ```
 
 ### Let-In
-
-Let-in allows the binding of an expression. It is used as
-`let <rec?> <ident> = <expr> in <expr>`. The `rec` keyword in Let-in constructs
-allows the let binding to become recursive, enabling the use of the `<ident>`
-within the first `<expr>`.
+Let-in allows the binding of an expression. It is used as `let <rec?> <ident> = <expr> in <expr>`.
+The `rec` keyword in Let-in constructs allows the let binding to become recursive, enabling the use of the `<ident>` within the first `<expr>`.
 
 Examples:
-
-```text
+```
 > let r = { a = "a", b = "b" } in r.a
 "a"
 
@@ -390,23 +353,17 @@ true
 > let rec fib = fun n => if n <= 2 then 1 else fib (n - 1) + fib (n - 2) in fib 9
 34
 
-> let rec repeat = fun n x => if n <= 0 then [] else repeat (n - 1) x @ [x] in
-repeat 3 "foo"
+> let rec repeat = fun n x => if n <= 0 then [] else repeat (n - 1) x @ [x] in repeat 3 "foo"
 ["foo", "foo", "foo"]
 ```
 
 ## Functions
-
-A function is declared using the `fun` keyword, then arguments separated with
-spaces, and finally an arrow `=>` to add the body of the function. To call a
-function, just add the arguments after it separated with spaces. Functions in
-Nickel are curried, meaning that a function taking multiple arguments is
-actually a function that takes a single argument and returns a function taking
-the rest of the arguments, until it is applied.
+A function is declared using the `fun` keyword, then arguments separated with spaces, and finally an arrow `=>` to add the body of the function.
+To call a function, just add the arguments after it separated with spaces.
+Functions in Nickel are curried, meaning that a function taking multiple arguments is actually a function that takes a single argument and returns a function taking the rest of the arguments, until it is applied.
 
 Examples:
-
-```text
+```
 > (fun a b => a + b) 1 2
 3
 
@@ -419,12 +376,10 @@ let add = fun a b => a + b in add 1 2
 3
 ```
 
-All existing infix operators in Nickel can be turned into functions by putting
-them inside parentheses.
+All existing infix operators in Nickel can be turned into functions by putting them inside parentheses.
 
 Examples:
-
-```text
+```
 > 1 + 2
 3
 
@@ -443,13 +398,11 @@ Examples:
 [ 1, 2, 3, 4, 5 ]
 ```
 
-Functions might be composed using the *pipe operator*. The pipe operator allows
-for a function application `f x` to be written as `x |> f`. This operator is
-left-associative, so `x |> f |> g` will be interpreted as `g (f x)`.
+Functions might be composed using the *pipe operator*. The pipe operator allows for a function application `f x` to be written as `x |> f`.
+This operator is left-associative, so `x |> f |> g` will be interpreted as `g (f x)`.
 
 Examples:
-
-```text
+```
 > "Hello World" |> string.split " "
 ["Hello", "World"]
 
@@ -466,12 +419,10 @@ Examples:
 ```
 
 ## Typing
-
-To give a type to a value, we write it with `< value > : < type >`. More
-information on typing in the relevant document.
+To give a type to a value, we write it with `< value > : < type >`.
+More information on typing in the relevant document.
 
 Examples:
-
 ```nickel
 5 : Num
 "Hello" : Str
@@ -487,14 +438,12 @@ let r : { _ : Num } = { a = 1, b = 2 }
 ```
 
 ## Metadata
+Metadata are used to attach contracts (more information in relevant documentation), documentation or priority to values.
+A metadata is introduced with the syntax `<value> | <metadata>`. Multiple metadata can be chained.
 
-Metadata are used to attach contracts (more information in relevant
-documentation), documentation or priority to values. A metadata is introduced
-with the syntax `<value> | <metadata>`. Multiple metadata can be chained.
 
 Examples:
-
-```text
+```
 > 5 | Num
 5
 
@@ -517,9 +466,9 @@ error: Blame error: contract broken by a value.
 3
 ```
 
-Adding documentation can be done with `| doc < string >`. Examples:
-
-```text
+Adding documentation can be done with `| doc < string >`.
+Examples:
+```
 > 5 | doc "The number five"
 5
 
@@ -532,13 +481,11 @@ Adding documentation can be done with `| doc < string >`. Examples:
 true
 ```
 
-Record contracts can set default values using the `default` metadata: It is
-noted as `| default = < default value >`. This is especially useful when merging
-records (more about this in the dedicated document about merge).
-
+Record contracts can set default values using the `default` metadata:
+It is noted as `| default = < default value >`.
+This is especially useful when merging records (more about this in the dedicated document about merge).
 Examples:
-
-```text
+```
 > let Ais2ByDefault = { a | default = 2 } in
   {} | Ais2ByDefault
 { a = 2 }
diff --git a/doc/manual/types-vs-contracts.md b/doc/manual/types-vs-contracts.md
index 525013eb..138b0726 100644
--- a/doc/manual/types-vs-contracts.md
+++ b/doc/manual/types-vs-contracts.md
@@ -40,7 +40,6 @@ What to do depends on the context:
     for the sake of clarity.
 
     Example:
-
     ```nickel
     let foo : Num =
       let addTwo = fun x => x + 2 in
@@ -61,7 +60,6 @@ Types are not adding much for configuration data, while contracts are more
 flexible and expressive.
 
 Example:
-
 ```nickel
 let Schema = {
   name | Str
diff --git a/doc/manual/typing.md b/doc/manual/typing.md
index 619f83fb..7b201815 100644
--- a/doc/manual/typing.md
+++ b/doc/manual/typing.md
@@ -44,7 +44,7 @@ example:
 `version` is a string, and can't be added to a number. If we try to export this
 configuration using `nickel export`, we get a reasonable error message:
 
-```text
+```
 error: Type error
   ┌─ repl-input-3:8:16
   │
@@ -68,8 +68,7 @@ filter (fun x => if x % 2 == 0 then x else null) [1,2,3,4,5,6]
 ```
 
 Result:
-
-```text
+```
 error: Type error
   ┌─ repl-input-11:2:32
   │
@@ -103,7 +102,6 @@ annotation. We will refer to such an annotated expression as a *statically typed
 block*.
 
 Example:
-
 ```nickel
 # Let binding
 let f : Num -> Bool = fun x => x % 2 == 0 in
@@ -128,8 +126,7 @@ filter (fun x => if x % 2 == 0 then x else null) [1,2,3,4,5,6]) : Array Num
 ```
 
 Result:
-
-```text
+```
 error: Incompatible types
   ┌─ repl-input-12:3:37
   │
@@ -173,29 +170,24 @@ The following type constructors are available:
 - **Array**: `Array T`. An array of elements of type `T`.
 
   Example:
-
   ```nickel
   let x : Array (Array Num) = [[1,2], [3,4]] in
   array.flatten x : Array Num
   ```
-
 - **Record**: `{field1: T1, .., fieldn: Tn}`. A record whose field
   names are known statically as `field1`, .., `fieldn`, respectively of type
   `T1`, .., `Tn`.
 
   Example:
-
   ```nickel
   let pair : {fst: Num, snd: Str} = {fst = 1, snd = "a"} in
   pair.fst : Num
   ```
-
 - **Dynamic record**: `{_: T}`. A record whose field
   names are statically unknown but are all of type `T`.  Typically used to model
   dictionaries.
 
   Example:
-
   ```nickel
   let occurrences : {_: Num} = {a = 1, b = 3, c = 0} in
   record.map (fun char count => count + 1) occurrences : {_ : Num}
@@ -208,7 +200,6 @@ The following type constructors are available:
   able to detect incomplete matches, for example.
 
   Example:
-
   ```nickel
   let protocol : [| `http, `ftp, `sftp |] = `http in
   (switch {
@@ -218,12 +209,10 @@ The following type constructors are available:
   } protocol) : Num
   ```
 
-- **Arrow (function)**: `S -> T`. A function taking arguments of type `S` and
-  returning a value of type `T`. For multi-parameters functions, just iterate
-  the arrow constructor.
+- **Arrow (function)**: `S -> T`. A function taking arguments of type `S` and returning a value of
+  type `T`. For multi-parameters functions, just iterate the arrow constructor.
 
   Example:
-
   ```nickel
   {
     incr : Num -> Num = fun x => x + 1,
@@ -296,8 +285,7 @@ result) : Array Num
 ```
 
 Result:
-
-```text
+```
 error: Incompatible types
   ┌─ repl-input-35:2:37
   │
@@ -344,7 +332,7 @@ let r3 = {may = 1300, june = 400, total = may + june} in
 }) : {partial1: Num, partial2: Num}
 ```
 
-```text
+```
 error: Type error: extra row `sept`
   ┌─ repl-input-40:8:23
   │
@@ -380,7 +368,6 @@ let r3 = {may = 1300, june = 400, total = may + june} in
 ```
 
 Result:
-
 ```nickel
 {partial1 = 570, partial2 = 1770}
 ```
@@ -451,8 +438,7 @@ array.filter (fun x => if x % 2 == 0 then x else null) [1,2,3,4,5,6]
 ```
 
 Result:
-
-```text
+```
 error: Blame error: contract broken by the caller.
   ┌─ :1:17
   │
@@ -489,11 +475,11 @@ We call `filter` from a dynamically typed location, but still get a spot-on
 error. To precisely avoid dynamically code injecting values of the wrong type
 inside statically typed blocks via function calls, the interpreter protects said
 blocks by a contract. Contracts form a principled runtime verification scheme.
-Please refer to the [dedicated manual section](./contracts.md) for more details,
-but for now, you can just remember that *any type annotation* (wherever it is)
-gives rise at runtime to a corresponding contract application. In other words,
-`foo: T` and `foo | T` (here `|` is contract application, not the row tail
-separator) behave exactly the same at *runtime*.
+Please refer to the [dedicated manual section](./contracts.md) for more details, but
+for now, you can just remember that *any type annotation* (wherever it is) gives
+rise at runtime to a corresponding contract application. In other words, `foo:
+T` and `foo | T` (here `|` is contract application, not the row tail separator)
+behave exactly the same at *runtime*.
 
 Thanks to this guard, you can statically type your library functions and use
 them from dynamically typed code while still enjoying good error messages.
@@ -510,8 +496,7 @@ let x = 0 + 1 in
 ```
 
 Result:
-
-```text
+```
 error: Incompatible types
   ┌─ repl-input-6:1:6
   │
@@ -529,7 +514,6 @@ evaluates to a number but is rejected by the typechecker because it uses dynamic
 idioms. In this case, we can trade a type annotation for a contract application:
 
 Example:
-
 ```nickel
 let x | Num = if true then 0 else "a" in
 (1 + x : Num)
@@ -560,8 +544,7 @@ because of the type mismatch between the if branches:
 ```
 
 Result:
-
-```text
+```
 error: Incompatible types
   ┌─ repl-input-46:1:27
   │
@@ -573,9 +556,10 @@ error: Incompatible types
   = These types are not compatible
 ```
 
-**Apparent type**: As a side note, annotations are not always needed to use
-dynamically typed code inside a statically typed block. The following example is
-accepted:
+**Apparent type**
+
+As a side note, annotations are not always needed to use dynamically typed code
+inside a statically typed block. The following example is accepted:
 
 ```nickel
 let x = 1 in
@@ -613,9 +597,8 @@ typechecker on, a contract annotation switches it back off.
 
 **Warning**: as of version 0.2.x, using contracts as types won't work in the
 majority of cases (typechecking will fail with a "can't compare contract types"
-error). This is temporary and will likely be fixed in the upcoming 0.3.x
-release. For more details, see issues
-[#701](https://github.com/tweag/nickel/issues/701) and
+error). This is temporary and will likely be fixed in the upcoming 0.3.x release. For more
+details, see issues [#701](https://github.com/tweag/nickel/issues/701) and
 [#724](https://github.com/tweag/nickel/issues/724).
 
 <!-- TODO: find a good name for this section. Will need rework after merging
@@ -638,8 +621,7 @@ let Port = contract.from_predicate (fun value =>
 But this program is unfortunately rejected by the typechecker:
 
 Result:
-
-```text
+```
 error: Incompatible types
   ┌─ repl-input-0:7:2
   │
diff --git a/examples/README.md b/examples/README.md
index 9e26d786..7de5e89f 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -11,19 +11,15 @@ data!
 
 ### From the command line
 
-- *Base values*: some examples just return numbers, strings or booleans. You can
-  run them directly:
-
-    ```console
+- *Base values*: some examples just return numbers, strings or booleans. You can run them directly:
+    ```
     $ nickel -f fibonacci.ncl
-    55
+    Done: Num(55.0)
+    ```
+- *Configurations*: some return records representing configuration. Because of laziness, Nickel
+    won't currently print any readable result as is. Please use the `export`
+    subcommand to see the result serialized as JSON:
     ```
-
-- *Configurations*: some return records representing configuration. Nickel won't
-  currently print a very readable result as is. Please use the `export`
-  subcommand to see the result serialized as JSON:
-
-    ```console
     $ nickel -f merge-main.ncl export
     {
       "firewall": {
@@ -34,7 +30,7 @@ data!
     Alternatively, you can query a configuration or a sub-element to get
     a list of attributes or the documentation:
 
-    ```console
+    ```
     $ nickel -f record-contract.ncl query kind
       • contract: <ReplicationController, ReplicaSet, Pod>
       • value: `ReplicationController
@@ -45,41 +41,38 @@ data!
 
 First start the REPL:
 
-```console
+```
 $ nickel repl
 nickel>
 ```
 
 - Just import a file directly to evaluate it:
-
-    ```text
+    ```
     nickel> import "fibonacci.ncl"
     55
 
     nickel>
     ```
-
 - Use `builtin.serialize` to have the same behavior as the `export` subcommand
   and print the result as JSON:
 
-    ```text
-    nickel> builtin.serialize `Json (import "merge-main.ncl")
-    "{
-        \"firewall\": {
-        ...
-    }"
-
-    nickel>
-    ```
+  ```
+  nickel> builtin.serialize `Json (import "merge-main.ncl")
+  "{
+      \"firewall\": {
+      ...
+  }"
 
+  nickel>
+  ```
 - Use `:query` to retrieve information and documentation about a field:
 
-    ```text
-    nickel>let config = import "record-contract.ncl"
-    nickel>:query config.kind
-    • contract: <ReplicationController, ReplicaSet, Pod>
-    • value: `ReplicationController
-    • documentation: The kind of the element being configured.
+  ```
+  nickel>let config = import "record-contract.ncl"
+  nickel>:query config.kind
+  • contract: <ReplicationController, ReplicaSet, Pod>
+  • value: `ReplicationController
+  • documentation: The kind of the element being configured.
 
-    nickel>
-    ```
+  nickel>
+  ```
diff --git a/examples/arrays/README.md b/examples/arrays/README.md
index 66f66b6d..295f5c56 100644
--- a/examples/arrays/README.md
+++ b/examples/arrays/README.md
@@ -1,4 +1,4 @@
-# Arrays
+# Arrays 
 
 This example shows how to write generic, statically typed functions in Nickel.
 The code is illustrative: in practice, you should use the array stdlib functions
@@ -6,8 +6,8 @@ The code is illustrative: in practice, you should use the array stdlib functions
 
 ## Run
 
-```console
-nickel -f arrays.ncl export
+```
+$ nickel -f arrays.ncl export
 ```
 
 ## Playground
@@ -19,7 +19,7 @@ Another aspect is how Nickel guard typed function from untyped code by using
 contracts: at the end of the example, you can provide wrong arguments in the
 calls to `my_array_lib.map` or `my_array_lib.fold` to see contracts error appear:
 
-```diff
+```
 -    let l = my_array_lib.map (fun x => x+1) [1, 2, 3, 4, 5, 6] in
 +    let l = my_array_lib.map [1, 2, 3, 4, 5, 6] (fun x => x+1) in
 ```
diff --git a/examples/config-gcc/README.md b/examples/config-gcc/README.md
index 59c032d5..1702c14a 100644
--- a/examples/config-gcc/README.md
+++ b/examples/config-gcc/README.md
@@ -5,8 +5,8 @@ invocation of the `gcc` compiler.
 
 ## Run
 
-```console
-nickel -f config-gcc.ncl export
+```
+$ nickel -f config-gcc.ncl export
 ```
 
 ## Contracts
diff --git a/examples/fibonacci/README.md b/examples/fibonacci/README.md
index 7163bf6e..13d63a17 100644
--- a/examples/fibonacci/README.md
+++ b/examples/fibonacci/README.md
@@ -5,6 +5,6 @@ exponential version of fibonacci: don't call it on a big value!
 
 ## Run
 
-```console
-nickel -f fibonacci.ncl
+```
+$ nickel -f fibonacci.ncl
 ```
diff --git a/examples/merge/README.md b/examples/merge/README.md
index 8f1228e7..52f63688 100644
--- a/examples/merge/README.md
+++ b/examples/merge/README.md
@@ -6,6 +6,6 @@ code to run lies in `main.ncl`. The default value `firewall.enabled` defined in
 
 ## Run
 
-```console
-nickel -f main.ncl export
+```
+$ nickel -f main.ncl export
 ```
diff --git a/examples/polymorphism/README.md b/examples/polymorphism/README.md
index 74ae4447..5892b182 100644
--- a/examples/polymorphism/README.md
+++ b/examples/polymorphism/README.md
@@ -8,8 +8,8 @@ polymorphic types for you.
 
 ## Run
 
-```console
-nickel -f polymorphism.ncl
+```
+$ nickel -f polymorphism.ncl
 ```
 
 ## Playground
diff --git a/examples/record-contract/README.md b/examples/record-contract/README.md
index 3ee34af6..b0fc5511 100644
--- a/examples/record-contract/README.md
+++ b/examples/record-contract/README.md
@@ -7,8 +7,8 @@ configuration.
 
 ## Run
 
-```console
-nickel -f record-contract.ncl export
+```
+$ nickel -f record-contract.ncl export
 ```
 
 ## Playground
diff --git a/examples/simple-contracts/README.md b/examples/simple-contracts/README.md
index c1a7e38b..b39d4e8f 100644
--- a/examples/simple-contracts/README.md
+++ b/examples/simple-contracts/README.md
@@ -16,9 +16,9 @@ Bool` and use `contract.fromPred` to obtain the corresponding contracts.
 
 ## Run
 
-```console
-nickel -f simple-contract-bool.ncl
-nickel -f simple-contract-div.ncl
+```
+$ nickel -f simple-contract-bool.ncl
+$ nickel -f simple-contract-div.ncl
 ```
 
 ## Playground
diff --git a/flake.nix b/flake.nix
index f1b725e0..e118095e 100644
--- a/flake.nix
+++ b/flake.nix
@@ -168,13 +168,6 @@
                 enable = true;
                 entry = pkgs.lib.mkForce "${rust}/bin/cargo-fmt fmt -- --check --color always";
               };
-              markdownlint = {
-                enable = true;
-                excludes = [
-                  "notes/(.+)\\.md$"
-                  "^RELEASES\\.md$"
-                ];
-              };
             };
           };
 
@@ -305,7 +298,7 @@
           for file in *
           do
             module=$(basename $file .ncl)
-            ${self.packages."${system}".default}/bin/nickel doc -f "$module.ncl" \
+            ${self.defaultPackage."${system}"}/bin/nickel doc -f "$module.ncl" \
               --output "$out/$module.md"
           done
         '';
@@ -313,8 +306,8 @@
 
     in
     rec {
+      defaultPackage = packages.build;
       packages = {
-        default = packages.build;
         build = buildNickel { };
         buildWasm = buildNickelWasm { optimize = true; };
         dockerImage = buildDocker packages.build; # TODO: docker image should be a passthru
@@ -323,19 +316,17 @@
         inherit stdlibDoc;
       };
 
-      devShells = {
-        default = devShells.stable;
-      } // (forEachRustChannel
+      devShell = devShells.stable;
+      devShells = forEachRustChannel
         (channel: {
           name = channel;
           value = buildNickel { inherit channel; isDevShell = true; };
-        }
-        ));
+        });
 
       checks = {
         # wasm-opt can take long: eschew optimizations in checks
         wasm = buildNickelWasm { channel = "stable"; optimize = false; };
-        pre-commit = packages.default.pre-commit;
+        pre-commit = defaultPackage.pre-commit;
       } // (forEachRustChannel (channel:
         {
           name = "nickel-against-${channel}-rust-channel";
diff --git a/lsp/README.md b/lsp/README.md
index edc651bd..8f9681cb 100644
--- a/lsp/README.md
+++ b/lsp/README.md
@@ -30,32 +30,27 @@ the following commands.
 - *Global installation*: if you want to use `nls` on a regular basis, this is
   what you want to do. To have `nickel` and `nls` available globally, add them
   into your profile:
-
-    ```console
-    nix profile install github:tweag/nickel
-    ```
-
+  ```
+  nix profile install github:tweag/nickel
+  ```
 - *Shell*: Try out for the time of a session. To be dropped in a shell with the
   `nickel` and `nls` commands available, run:
-
-    ```console
-    nix shell github:tweag/nickel
-    ```
-
+  ```
+  nix shell github:tweag/nickel
+  ```
 - *Local build*: if you just wand to build `nickel`
-  and `nls` without installing them (the executables will be placed in
-  ./result/bin/):
-
-    ```shell
-    nix build github:tweag/nickel
-    ```
+  and `nls` without installing them:
+  ```
+  # The executables will be placed in ./result/bin/
+  nix build github:tweag/nickel
+  ```
 
 ### Using Nix (without flakes)
 
 Alternatively, you can install `nickel` and `nls` globally on older Nix versions
 without flakes via `nix-env`:
 
-```console
+```
 git clone https://github.com/tweag/nickel.git
 cd nickel
 nix-env -f . -i
@@ -66,7 +61,7 @@ nix-env -f . -i
 If you already have a working [`cargo`](https://doc.rust-lang.org/cargo/)
 installation, you can make `nls` available globally without Nix:
 
-```console
+```
 cargo install nickel-lang-lsp
 ```
 
@@ -87,43 +82,35 @@ your editor.
 #### Build the extension
 
 NLS is currently not available through the vscode marketplace, but this
-repository includes an extension that can be built locally via Nix (see the
-section about the Nix setup).
+repository includes an extension that can be built locally via Nix (cf []()
+about the Nix setup).
 
-- One-liner (using the [jq](https://stedolan.github.io/jq/) command):
-
-  ```console
+- One-liner (using the [`jq`](https://stedolan.github.io/jq/) command):
+  ```
   code --install-extension $(nix build ./\#vscodeExtension --no-link --json | jq ".[0].outputs.vsix")
   ```
-
 - In two steps, going via VSCode:
   - Build with Nix:
-
-      ```console
-      nix build github:tweag/nickel#vscodeExtension.vsix
-      ```
-
-  - Then, in VSCode, use "Extension: Install from VSIX" in the vscode command
+    ```
+    nix build github:tweag/nickel#vscodeExtension.vsix
+    ```
+  - Then, in VSCode, use `Extension: Install from VSIX` in the vscode command
     palette and choose `./result-vsix/nls-client.vsix`.
 
 #### Configuration
 
-The VS Code extension offers three configuration options:
+The VS Code extension offers three configuration options: 
 
 - `nls.server.path`: Path to nickel language server
 - `nls.server.trace`: Enables performance tracing to the given file
-- `nls.server.debugLog`: Logs the communication between VS Code and the language
-  server.
+- `nls.server.debugLog`: Logs the communication between VS Code and the language server.
 
 ### (Neo)Vim
 
-Before proceeding install the [Nickel syntax highlighting
-plugin](https://github.com/nickel-lang/vim-nickel) using your Vim plugin
-manager. Without this plugin your LSP client may not start NLS on nickel source
-files.
+Before proceeding install the [Nickel syntax highlighting plugin](https://github.com/nickel-lang/vim-nickel) using your Vim plugin manager.
+Without this plugin your LSP client may not start NLS on nickel source files.
 
 With Vim-Plug:
-
 ```vim
 Plug 'nickel-lang/vim-nickel'
 ```
@@ -141,25 +128,24 @@ require('lspconfig')["nickel_ls"].setup {}
 
 #### With Coc.nvim
 
-Add an `nickel_ls` entry to your configuration. Type `:CocConfig` in Neovim (or
-edit `coc-settings.json`) and add:
+Add an `nickel_ls` entry to your configuration. Type `:CocConfig` in Neovim (or edit `coc-settings.json`) and add:
 
-```jsonc
+```
 {
   "languageserver": {
-    // Your other language servers configuration
-    // ...,
+    # Your other language servers configuration
+    # ...,
     "nickel_ls": {
       "command": "nls",
-      // You can enable performance tracing with:
-      // "command": "nls --trace <file>",
+      # You can enable performance tracing with:
+      # "command": "nls --trace <file>",
       "rootPatterns": [
         ".git"
       ],
       "filetypes": [
         "ncl"
       ]
-    }
+    },
   }
 }
 ```
diff --git a/rfcs/001-overriding.md b/rfcs/001-overriding.md
index 8b451c20..3299db31 100644
--- a/rfcs/001-overriding.md
+++ b/rfcs/001-overriding.md
@@ -26,7 +26,7 @@ nested record.
 A naive and unergonomic of way of doing it is to repeat all the original
 values in a new record:
 
-```nickel
+```
 let record = {
   a = 1,
   b = "str",
@@ -97,7 +97,6 @@ changing an option, I usually want other values depending on this option to be
 updated as well.
 
 ## Comparing override mechanisms
-
 We are going to review various overriding mechanisms of Nix and other related
 languages. Let us sketch some general traits of overriding mechanisms as a
 framework for comparison:
@@ -186,12 +185,11 @@ overriding](https://nixos.org/guides/nix-pills/override-design-pattern.html) or
 
 #### Limits
 
-- ~~**(ERG)**~~ Use a specific representation, rather than handling good old
-  plain records (although the actual representation in Nixpkgs is more ergonomic
-  than a plain function).
-- ~~**(NEST)**~~ Overriding nested attribute sets is painful. If one do the
-  naive thing, the whole subrecord is erased:
-
+- ~~**(ERG)**~~ Use a specific representation, rather than handling good old plain records
+  (although the actual representation in Nixpkgs is more ergonomic than a plain
+  function).
+- ~~**(NEST)**~~ Overriding nested attribute sets is painful. If one do the naive thing,
+  the whole subrecord is erased:
   ```nix
   let rRepr = self: {
     a = {b = self.a.c;};
@@ -244,7 +242,6 @@ dedicated helper functions.
   logical structure.
 - ~~**(NEST)**~~ Overriding nested fields is still clumsy. For example, to
   override `lib.firefoxVersion`:
-
   ```nix
   self: super: { lib = (super.lib or {}) // { firefoxVersion = ...; }; }
   ```
@@ -301,7 +298,6 @@ someModule.paths = [/bar/baz];
     unspecified order.
 
     For example, the following has no equivalent in a merging model:
-
     ```nix
     let overlay = self: super: {b = self.c + 1; a = super.c + 1;}; in #...
     ```
@@ -313,11 +309,10 @@ and this limitation of expressivity may in fact be a good thing.
 ## Overriding elsewhere
 
 ### CUE
-
 CUE allows a form of late-binding for recursive attributes:
 
-```console
-$ cat test.cue
+```
+$cat test.cue
 fields: {
  a: int
  b: a + 1
@@ -334,8 +329,8 @@ fields: {
 Combined with [default values](https://cuelang.org/docs/tutorials/tour/types/defaults/),
 this provides an overriding mechanism:
 
-```console
-$ cat test2.cue
+```
+$cat test2.cue
 fields: {
  a: int | *1
  b: a + 1
@@ -403,7 +398,6 @@ the same way as Nixpkgs overlays, using the `super` keyword.
 
 While not exactly the same, all these overriding mechanisms are based on the
 same underlying principles:
-
 1. Represent recursive records (explicitly or implicitly) as a function of
    `self` (and `super` in some cases)
 2. Compute the combination as a **fixpoint** of several recursive records,
@@ -445,19 +439,23 @@ are required to be grouped in layers of the same priority, instead of logically.
 Summing up the differences between inheritance-based mechanisms and merge-based
 mechanism:
 
-**order-dependency**: Inheritance is order dependent: the chain of extensions
-must be defined with the precise order they will be applied in mind, and
-definitions must be grouped in consequence. On the other hand, merging is
-commutative, and the precedence information is encoded as priorities. Thus,
-overriding by merging can be defined using stand-alone pieces of data, although
-the behavior of priorities is not local.
+**order-dependency**
 
-**(EXP)**: Merged records have only access to the final computed fixpoint
-`self`, while objects have access to the previous stage of extension via
-`super`. However, as in the NixOS module system, it is possible to address this
-issue using custom merge functions. This is a bit less expressive, but in a good
-way: it forces the merge strategy to be uniform along each field, while
-mechanisms like overlays or inheritance can do pretty much anything.
+Inheritance is order dependent: the chain of extensions must be defined with the
+precise order they will be applied in mind, and definitions must be grouped in
+consequence. On the other hand, merging is commutative, and the precedence
+information is encoded as priorities. Thus, overriding by merging can be defined
+using stand-alone pieces of data, although the behavior of priorities is not
+local.
+
+**(EXP)**
+
+Merged records have only access to the final computed fixpoint `self`, while
+objects have access to the previous stage of extension via `super`. However, as
+in the NixOS module system, it is possible to address this issue using custom
+merge functions. This is a bit less expressive, but in a good way: it forces the
+merge strategy to be uniform along each field, while mechanisms like overlays or
+inheritance can do pretty much anything.
 
 ## Proposal overview
 
@@ -483,12 +481,12 @@ constructors - that take a `self` parameter and return a final non recursive rec
 in the same way as the original overriding mechanism of Nixpkgs (the non-existing
 syntax `def := value` is used to insist on the fact that we are defining new objects):
 
-```text
+```
 r = {
   a = 1;
   b = a + 1;
 }
-# Definition of the representation of r
+// Definition of the representation of r
 repr(r) := fun self => {
   a = 1;
   b = self.a + 1;
@@ -497,13 +495,13 @@ repr(r) := fun self => {
 
 Field access amounts to compute a fix-point:
 
-```text
+```
 repr(r).foo := let fix = repr(r) fix in fix.foo
 ```
 
 Merging simply merges the underlying representations:
 
-```text
+```
 repr(r1) & repr(r2) := fun self => r1 self & r2 self
 ```
 
@@ -552,7 +550,7 @@ let block2 = {
   path = ["/bin"]
 } in
 
-# { path = ["usr/local/bin", "/bin"] }
+// { path = ["usr/local/bin", "/bin"] }
 block1 & block2
 ```
 
@@ -571,7 +569,7 @@ only invalidate `self` on a merge. Also, fields that do not depend on a
 recursive variable can be hoisted out of the function, using a representation
 like:
 
-```text
+```
 repr(r) := {
   a = 1;
   b = fun self => self.a + 1;
@@ -593,26 +591,22 @@ trade-off between implementation complexity and performance. See
 Should a record be able to access a yet undefined field because it is expected
 to be provided by a subsequent merge? Two possible approaches:
 
-- **dynamic scoping**: records can reference fields that are not explicitly
-  defined locally, such as:
-
-  ```nickel
-  {a = b} & {b = 1}
-  ```
-
-  Dynamic scoping have a number of issues, and is usually considered bad
-  practice.
-- **lexical scoping**: as currently, require self-referenced fields to be
-  defined locally. Note that thanks to contracts, one can require the existence
-  of a field without defining it. For example, we could write the previous
-  example as:
-
-  ```nickel
-  {a = b, b | Num} & {b = 1}
-  ```
-
-  This is also a better practice to explicitly state the fields whose presence
-  is assumed in general.
+ - **dynamic scoping**: records can reference fields that are not explicitly
+   defined locally, such as:
+   ```nickel
+   {a = b} & {b = 1}
+   ```
+   Dynamic scoping have a number of issues, and is usually considered bad
+   practice.
+ - **lexical scoping**: as currently, require self-referenced fields to be
+   defined locally. Note that thanks to contracts, one can require the existence
+   of a field without defining it. For example, we could write the previous
+   example as:
+   ```nickel
+   {a = b, b | Num} & {b = 1}
+   ```
+   This is also a better practice to explicitly state the fields whose presence
+   is assumed in general.
 
 This RFC proposes to adopt **lexical scoping**. We could have an even lighter
 syntax, such as `{a = b, b} & {b = 1}` for requiring the presence of a field
@@ -640,14 +634,13 @@ Integer priorities are specified using the `priority` keyword. Defining more
 than one priority in the same meta-value is an error.
 
 Example:
-
 ```nickel
 {
   foo | Num
       | default = 1,
 
   bar | Str,
-  # equivalent to `bar | Str | priority 0`
+  //equivalent to `bar | Str | priority 0`
 
   baz.boo.bor | priority -4 = "value",
 
@@ -667,16 +660,15 @@ described in [#279](https://github.com/tweag/nickel/issues/279). We define the
 new meta-values `default rec` and `force rec`, whose semantics are defined as:
 
 - `eval(expr | default rec)`: case of `eval(expr)`:
-  - `{field1 = value1, .., fieldn = valuen} | annots`:
-    `{field1 = (value1 | default rec aux), .., fieldn =
+  * `{field1 = value1, .., fieldn = valuen} | annots`: `{field1 = (value1 | default rec aux), .., fieldn =
       (valuen | default rec aux)} | annots`
-  - `v | annots` if `v` is not a record: `v | defaulted(annots)` where
+  * `v | annots` if `v` is not a record: `v | defaulted(annots)` where
       `defaulted(annots)` is defined below.
 
 - `defaulted(annots)`:
-  - if `annots` contains the priority metavalue `force`, then `defaulted(annots)
+  * if `annots` contains the priority metavalue `force`, then `defaulted(annots)
     := annots`
-  - otherwise, let `annots' | prio` be the decomposition of `annots` into a
+  * otherwise, let `annots' | prio` be the decomposition of `annots` into a
     priority `prio` (possibly empty) and the other metavalues, then
     `defaulted(annots) := annots' | default`
 
@@ -688,7 +680,6 @@ are written in a liberal way, in that they can be empty).
 default ones. The names `default rec/force rec` are just suggestions.
 
 Example:
-
 ```nickel
 let neutralConf = {
   foo = 1,
@@ -697,31 +688,31 @@ let neutralConf = {
 }
 
 let defaulted | default rec = neutralConf
-# ^ Will evaluate to:
-# {
-#   foo | default = 1,
-#   bar = {
-#     baz | default = "stuff",
-#     bar.blorg | default = false,
-#   },
-# }
-# This is different from `neutralConf | default`! The latter version
-# would be overrided at once, as illustrated below.
+// ^ Will evaluate to:
+// {
+//   foo | default = 1,
+//   bar = {
+//     baz | default = "stuff",
+//     bar.blorg | default = false,
+//   },
+// }
+// This is different from `neutralConf | default`! The latter version
+// would be overrided at once, as illustrated below.
 
 defaulted & {bar.baz = "shapoinkl"}
-# ^ Gives the expected:
-# {
-#   foo | default = 1,
-#   bar = {
-#     baz = "shapoinkl";
-#     bar.blor | default = false,
-#   },
-# }
-# While
+// ^ Gives the expected:
+// {
+//   foo | default = 1,
+//   bar = {
+//     baz = "shapoinkl";
+//     bar.blor | default = false,
+//   },
+// }
+// While
 
 (neutralConf | default) & {bar.baz = "shapoinkl"}
-# ^ This gives only:
-# {bar.baz = "shapoinkl"}
+// ^ This gives only:
+// {bar.baz = "shapoinkl"}
 ```
 
 This way, an existing definition (arbitrarily complex: that could be the root of
@@ -730,7 +721,7 @@ overridable configuration. A possible extension is to have a user-provided
 function that is mapped on priotities: `default/force rec` are just special
 cases of this.
 
-### Custom merge functions 2
+### Custom merge functions
 
 In the case of the NixOS module system, all the configuration is merged in one
 final phase that conceptually evaluates the merge AST.
@@ -750,15 +741,15 @@ let add = fun args => args.lower + args.higher in
 But what about `{a = 1} & {a | merge add = 1} & {a = 2}`? If a merge annotation
 only affects terms on the right hand side, this breaks commutativity.
 
-```nickel
+```
 let r1 = {a = 1} in
 let r2 = {a = 1} in
 let r3 = {a | merge add = 1} in
 
-# {val = 2}
+// {val = 2}
 r1 & r2 & r3
 
-# {val = 3}
+// {val = 3}
 r3 & r1 & r2
 ```
 
@@ -792,7 +783,7 @@ This RFC proposes solution 2. This raises some difficulties:
   In some sense, we would like to have a call-by-name semantics rather than a
   call-by-need.
 
-  - (a) In the case of record fields, overriding has to solve the
+  * (a) In the case of record fields, overriding has to solve the
     same problem of remembering an original expression along an evaluated version.
     If we allow custom merge annotations only on record fields, it is possible to
     recover the original merge AST (abstract syntax tree) and interpret it with
@@ -800,7 +791,7 @@ This RFC proposes solution 2. This raises some difficulties:
     in practice, for the merge expression `val1 & val2` may be obfuscated by some
     program transformations or evaluation artifacts, but doable.
 
-  - (b) A more extreme take is to generalize this to any term: a
+  * (b) A more extreme take is to generalize this to any term: a
     merge expression would behave like a lazy datatype `Merge(t1,t2)` with
     respect to evaluation. Evaluating it would amount to automatically apply
     `eval : Merge(t1,t2) -> t1 & t2` with a potential merge function, which
@@ -829,21 +820,21 @@ Let us define the notion of a *merge tree*. The definition determines what is
 the area of influence of a merge function annotation, answering the following
 questions:
 
-```nickel
+```
 let add = fun x y => x + y in
 
 let var = 1 & 1 in
-var & (1 | merge add) # result?
-(var | merge add) & 1 # result?
+var & (1 | merge add) // result?
+(var | merge add) & 1 // result?
 
-((1 & 1) + (1 & 1)) & (1 | merge add) # result?
-((1 & 1) + (1 & 1) | merge add) & 1 # result?
+((1 & 1) + (1 & 1)) & (1 | merge add) // result?
+((1 & 1) + (1 & 1) | merge add) & 1 // result?
 
-# file: somefile.ncl
+// file: somefile.ncl
 1 & 1
-# file: other.ncl
-(import "somefile") & (1 | merge add) # result?
-(import "somefile" | merge add) & 1 # result?
+// file: other.ncl
+(import "somefile") & (1 | merge add) // result?
+(import "somefile" | merge add) & 1 // result?
 ```
 
 In the following, we will write "meta"-code (think of the code of the Nickel
@@ -881,8 +872,8 @@ expression. It needs to evaluate leafs to see if they contains themselves merge
 expressions, such that `let x = a & b in x & c` and `a & b & c` has the same
 merge tree: that is, merge treee commute with evaluation.
 
-```text
-# we maintain an environment of bindings in `env`
+```
+// we maintain an environment of bindings in `env`
 
 metaData [| e | attr = val, ... |] ::=
   { attr = val, ... }                    if priority is set
@@ -907,7 +898,7 @@ absMergeTree e = weakEval e
 weakEval [| e1 & e2 |] @ e = e
 
 // all other cases are defined exactly as for eval
-weakEval e = ...
+weakEval e = ... 
 ```
 
 ### Semantics
@@ -915,7 +906,7 @@ weakEval e = ...
 Now that we defined merge trees, we need to extract a potential merge fonction
 from it:
 
-```text
+```
 type MergeFunction =
   {value: Dyn, priority: Priority} ->
   {value: Dyn, priority: Priority} -> Dyn
@@ -938,7 +929,7 @@ mergeFunction t = let funs = extractMergeFuns t in
 
 And the interpretation of a merge tree by a merge function:
 
-```text
+```
 // can be extended, as long as it is a partially ordered set
 Priority = Number | -inf | +inf | ...
 
@@ -951,7 +942,7 @@ interpret (Merge(ast_1,meta_1),Merge(ast_2,meta_2)) f =
 
 We can finally define the evaluation of merge:
 
-```text
+```
 eval [| e1 & e2 |] =
   let t = mergeTree [| e1 & e2 |] in
   interpret t (mergeFunction t)
diff --git a/rfcs/002-merge-types-terms-syntax.md b/rfcs/002-merge-types-terms-syntax.md
index 9bc91690..6d322668 100644
--- a/rfcs/002-merge-types-terms-syntax.md
+++ b/rfcs/002-merge-types-terms-syntax.md
@@ -37,8 +37,8 @@ is different from the standard typed functional language. We have to:
   exists in the language.
 
 Thus, we can precisely give a meaning to a type `1 + 1` (`#(1 + 1)`) and to a
-term such as `forall a. a -> a` (`§(forall a. a -> a)`). Why we propose to do so
-is explained in the next section.
+term such as `forall a. a -> a` (`§(forall a. a -> a)`). Why we propose to do so is
+explained in the next section.
 
 ## Motivation
 
@@ -98,7 +98,6 @@ that we could just write:
 Which looks more natural all while having a reasonable semantics.
 
 ## Notations
-
 We use the following notations throughout this document:
 
 - `Term` is the subset of the current syntax that includes terms: records,
@@ -229,9 +228,9 @@ complex, whenever possible.
 - Recall that `! : Term + Type -> UniTerm` is the embedding of the current
   syntax to the new unified syntax (erasing `#` and `§`, and changing `|` for
   tails to `;`)
-- In the following, `~` is some flavour of operational equivalence. We won't
-  prove the rules. Those are rather design guidelines. In consequence, we also
-  restrain from giving a formal definition for `~`.
+- In the following, `~` is some flavour of operational equivalence. We won't prove the rules.
+  Those are rather design guidelines. In consequence, we also restrain from
+  giving a formal definition for `~`.
 
 The `term` and `type` functions must satisfy the following coherence laws:
 
@@ -301,7 +300,7 @@ typechecking but fails at runtime on the failure of merging `1` and `2`.
 Because of those issues, **we propose to only translate as types records that
 are already record types in the current syntax**. That is:
 
-```text
+```
 type({f1: t1, .., fn : tn}) = {f1: type(t1), .., fn: type(tn)}
 type({...}) = #term({...}) otherwise
 ```
@@ -314,11 +313,11 @@ possible improvements.
 There is currently no general type application per se, but a special casing for
 `List Foo`, which is a parametrized type. **We propose to keep ground types as
 reserved keywords and special lexemes of the language** for now: it makes things
-simpler as we don't have to ask ourselves what `let List = 1 in [] : List Num`
-should be interpreted as. That way, we can also special case the application of
-the list type and translate an application as a term otherwise:
+simpler as we don't have to ask ourselves what `let List = 1 in [] : List Num` should be
+interpreted as. That way, we can also special case the application of the list
+type and translate an application as a term otherwise:
 
-```text
+```
 type(a b) = List type(f)   if a == List
           = #term(a b)     otherwise (= #term(a) term(b))
 ```
@@ -361,7 +360,7 @@ or not. We sidestep this question as an external implementation detail, assuming
 here that there is a predicate `is_type_var` available during the translation.
 We can now set:
 
-```text
+```
 type(var x) = x   if is_type_var(x)
 type(var x) = #x  otherwise
 ```
@@ -380,7 +379,7 @@ types in the current syntax. It turns out we could extract record types from
 some record contracts too, that often hold the same information. The typical
 example is contracts of the form:
 
-```nickel
+```
 {
   foo | #Contract1,
   bar | #{baz | Str},
@@ -449,7 +448,7 @@ benefit in allowing it would be to capture type variables, as in
 We can even imagine the typechecker being able to evaluate function application,
 to be able to do something like:
 
-```nickel
+```
 let Pair = fun a b => {fst: a, snd: b} in
 fst : forall a b. Pair a b -> a = ...
 ```
diff --git a/src/parser/grammar.lalrpop b/src/grammar.lalrpop
similarity index 100%
rename from src/parser/grammar.lalrpop
rename to src/grammar.lalrpop
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 72b8b6ed..d9617000 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -8,7 +8,7 @@ lalrpop_mod!(
     #[allow(clippy::all)]
     #[allow(unused_parens)]
     #[allow(unused_imports)]
-    pub grammar, "/parser/grammar.rs");
+    pub grammar);
 
 pub mod error;
 pub mod lexer;
diff --git a/stdlib/array.ncl b/stdlib/array.ncl
index 75b3788a..10e9ab92 100644
--- a/stdlib/array.ncl
+++ b/stdlib/array.ncl
@@ -260,13 +260,13 @@
 
         For example:
         ```nickel
-          sort (fun x y => if x < y then `Less else if (x == y) then `Equal else `Greater) [ 4, 5, 1, 2 ] =>
+          sort (fun x y => if x < y then `Lesser else if (x == y) then `Equal else `Greater) [ 4, 5, 1, 2 ] =>
             [ 1, 2, 4, 5 ]
         ```
         "%m
       = fun cmp l =>
         let first = %head% l in
-        let parts = partition (fun x => (cmp x first == `Less)) (%tail% l) in
+        let parts = partition (fun x => (cmp x first == `Lesser)) (%tail% l) in
         if %length% l <= 1 then
           l
         else


Test patch:
diff --git a/tests/pass/arrays.ncl b/tests/pass/arrays.ncl
index 55cc54a2..6933a786 100644
--- a/tests/pass/arrays.ncl
+++ b/tests/pass/arrays.ncl
@@ -10,6 +10,13 @@ let Assert = fun l x => x || %blame% l in
   array.length [1,2,3] == 3,
   array.length ([] @ [1,2] @ [3,4] @ []) == 4,
 
+  # sort
+  let cmp = fun x y =>
+    if x < y then `Lesser
+    else if x == y then `Equal
+    else `Greater
+  in array.sort cmp [3, 42, -1, -5] == [-5, -1, 3, 42],
+
   # Test case added after https://github.com/tweag/nickel/issues/154
   let x = 1 in let l = [x] @ [2] in %head% l == 1,