Browse Source

Merge pull request #566 from Bzero/example_decorator

Example decorators
David Peter 1 year ago
parent
commit
11c4d86cd5

+ 1 - 0
Cargo.lock

@@ -1089,6 +1089,7 @@ dependencies = [
  "num-traits",
  "numbat-exchange-rates",
  "once_cell",
+ "percent-encoding",
  "plotly",
  "pretty_dtoa",
  "rand",

+ 4 - 0
book/build.py

@@ -1,6 +1,7 @@
 import subprocess
 from pathlib import Path
 import urllib.parse
+import os
 
 
 SCRIPT_DIR = Path(__file__).parent.resolve()
@@ -119,6 +120,8 @@ def list_of_functions(file_name, document):
                 print(
                     f"Generating list of functions for module '{module}'...", flush=True
                 )
+                env = os.environ.copy()
+                env["TZ"] = "UTC"
                 subprocess.run(
                     [
                         "cargo",
@@ -132,6 +135,7 @@ def list_of_functions(file_name, document):
                     ],
                     stdout=f,
                     text=True,
+                    env=env,
                 )
 
 

+ 136 - 0
book/src/list-functions-datetime.md

@@ -18,6 +18,26 @@ Parses a string (date and time) into a `DateTime` object. See [here](./date-and-
 fn datetime(input: String) -> DateTime
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=datetime%28%222022%2D07%2D20T21%3A52%2B0200%22%29')""></button></div><code class="language-nbt hljs numbat">>>> datetime("2022-07-20T21:52+0200")
+
+    = 2022-07-20 19:52:00 UTC    [DateTime]
+</code></pre>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=datetime%28%222022%2D07%2D20%2021%3A52%20Europe%2FBerlin%22%29')""></button></div><code class="language-nbt hljs numbat">>>> datetime("2022-07-20 21:52 Europe/Berlin")
+
+    = 2022-07-20 21:52:00 CEST (UTC +02), Europe/Berlin    [DateTime]
+</code></pre>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=datetime%28%222022%2F07%2F20%2009%3A52%20PM%20%2B0200%22%29')""></button></div><code class="language-nbt hljs numbat">>>> datetime("2022/07/20 09:52 PM +0200")
+
+    = 2022-07-20 21:52:00 (UTC +02)    [DateTime]
+</code></pre>
+
+</details>
+
 ### `format_datetime`
 Formats a `DateTime` object as a string.
 
@@ -25,6 +45,16 @@ Formats a `DateTime` object as a string.
 fn format_datetime(format: String, input: DateTime) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=format%5Fdatetime%28%22This%20is%20a%20date%20in%20%25B%20in%20the%20year%20%25Y%2E%22%2C%20datetime%28%222022%2D07%2D20%2021%3A52%20%2B0200%22%29%29')""></button></div><code class="language-nbt hljs numbat">>>> format_datetime("This is a date in %B in the year %Y.", datetime("2022-07-20 21:52 +0200"))
+
+    = "This is a date in July in the year 2022."    [String]
+</code></pre>
+
+</details>
+
 ### `get_local_timezone`
 Returns the users local timezone.
 
@@ -32,6 +62,16 @@ Returns the users local timezone.
 fn get_local_timezone() -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=get%5Flocal%5Ftimezone%28%29')""></button></div><code class="language-nbt hljs numbat">>>> get_local_timezone()
+
+    = "UTC"    [String]
+</code></pre>
+
+</details>
+
 ### `tz`
 Returns a timezone conversion function, typically used with the conversion operator.
 
@@ -39,6 +79,21 @@ Returns a timezone conversion function, typically used with the conversion opera
 fn tz(tz: String) -> Fn[(DateTime) -> DateTime]
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=datetime%28%222022%2D07%2D20%2021%3A52%20%2B0200%22%29%20%2D%3E%20tz%28%22Europe%2FAmsterdam%22%29')""></button></div><code class="language-nbt hljs numbat">>>> datetime("2022-07-20 21:52 +0200") -> tz("Europe/Amsterdam")
+
+    = 2022-07-20 21:52:00 CEST (UTC +02), Europe/Amsterdam    [DateTime]
+</code></pre>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=datetime%28%222022%2D07%2D20%2021%3A52%20%2B0200%22%29%20%2D%3E%20tz%28%22Asia%2FTaipei%22%29')""></button></div><code class="language-nbt hljs numbat">>>> datetime("2022-07-20 21:52 +0200") -> tz("Asia/Taipei")
+
+    = 2022-07-21 03:52:00 CST (UTC +08), Asia/Taipei    [DateTime]
+</code></pre>
+
+</details>
+
 ### `unixtime`
 Converts a `DateTime` to a UNIX timestamp. Can be used on the right hand side of a conversion operator: `now() -> unixtime`.
 
@@ -46,6 +101,16 @@ Converts a `DateTime` to a UNIX timestamp. Can be used on the right hand side of
 fn unixtime(input: DateTime) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=datetime%28%222022%2D07%2D20%2021%3A52%20%2B0200%22%29%20%2D%3E%20unixtime')""></button></div><code class="language-nbt hljs numbat">>>> datetime("2022-07-20 21:52 +0200") -> unixtime
+
+    = 1_658_346_720
+</code></pre>
+
+</details>
+
 ### `from_unixtime`
 Converts a UNIX timestamp to a `DateTime` object.
 
@@ -53,6 +118,16 @@ Converts a UNIX timestamp to a `DateTime` object.
 fn from_unixtime(input: Scalar) -> DateTime
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=from%5Funixtime%282%5E31%29')""></button></div><code class="language-nbt hljs numbat">>>> from_unixtime(2^31)
+
+    = 2038-01-19 03:14:08 UTC    [DateTime]
+</code></pre>
+
+</details>
+
 ### `today`
 Returns the current date at midnight (in the local time).
 
@@ -67,6 +142,16 @@ Parses a string (only date) into a `DateTime` object.
 fn date(input: String) -> DateTime
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=date%28%222022%2D07%2D20%22%29')""></button></div><code class="language-nbt hljs numbat">>>> date("2022-07-20")
+
+    = 2022-07-20 00:00:00 UTC    [DateTime]
+</code></pre>
+
+</details>
+
 ### `time`
 Parses a string (time only) into a `DateTime` object.
 
@@ -81,6 +166,16 @@ Adds the given time span to a `DateTime`. This uses leap-year and DST-aware cale
 fn calendar_add(dt: DateTime, span: Time) -> DateTime
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=calendar%5Fadd%28datetime%28%222022%2D07%2D20%2021%3A52%20%2B0200%22%29%2C%202%20years%29')""></button></div><code class="language-nbt hljs numbat">>>> calendar_add(datetime("2022-07-20 21:52 +0200"), 2 years)
+
+    = 2024-07-20 21:52:00 (UTC +02)    [DateTime]
+</code></pre>
+
+</details>
+
 ### `calendar_sub`
 Subtract the given time span from a `DateTime`. This uses leap-year and DST-aware calendar arithmetic with variable-length days, months, and years.
 
@@ -88,6 +183,16 @@ Subtract the given time span from a `DateTime`. This uses leap-year and DST-awar
 fn calendar_sub(dt: DateTime, span: Time) -> DateTime
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=calendar%5Fsub%28datetime%28%222022%2D07%2D20%2021%3A52%20%2B0200%22%29%2C%203%20years%29')""></button></div><code class="language-nbt hljs numbat">>>> calendar_sub(datetime("2022-07-20 21:52 +0200"), 3 years)
+
+    = 2019-07-20 21:52:00 (UTC +02)    [DateTime]
+</code></pre>
+
+</details>
+
 ### `weekday`
 Get the day of the week from a given `DateTime`.
 
@@ -95,6 +200,16 @@ Get the day of the week from a given `DateTime`.
 fn weekday(dt: DateTime) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=weekday%28datetime%28%222022%2D07%2D20%2021%3A52%20%2B0200%22%29%29')""></button></div><code class="language-nbt hljs numbat">>>> weekday(datetime("2022-07-20 21:52 +0200"))
+
+    = "Wednesday"    [String]
+</code></pre>
+
+</details>
+
 ### `julian_date` (Julian date)
 Convert a `DateTime` to a Julian date, the number of days since the origin of the Julian date system (noon on November 24, 4714 BC in the proleptic Gregorian calendar).
 More information [here](https://en.wikipedia.org/wiki/Julian_day).
@@ -103,6 +218,16 @@ More information [here](https://en.wikipedia.org/wiki/Julian_day).
 fn julian_date(dt: DateTime) -> Time
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=julian%5Fdate%28datetime%28%222022%2D07%2D20%2021%3A52%20%2B0200%22%29%29')""></button></div><code class="language-nbt hljs numbat">>>> julian_date(datetime("2022-07-20 21:52 +0200"))
+
+    = 2.45978e+6 day    [Time]
+</code></pre>
+
+</details>
+
 ### `human` (Human-readable time duration)
 Converts a time duration to a human-readable string in days, hours, minutes and seconds.
 More information [here](https://numbat.dev/doc/date-and-time.html).
@@ -111,3 +236,14 @@ More information [here](https://numbat.dev/doc/date-and-time.html).
 fn human(time: Time) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+How long is a microcentury?
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=century%2F1e6%20%2D%3E%20human')""></button></div><code class="language-nbt hljs numbat">>>> century/1e6 -> human
+
+    = "52 minutes + 35.692505184 seconds"    [String]
+</code></pre>
+
+</details>
+

+ 229 - 0
book/src/list-functions-lists.md

@@ -9,6 +9,16 @@ Get the length of a list.
 fn len<A>(xs: List<A>) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=len%28%5B3%2C%202%2C%201%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> len([3, 2, 1])
+
+    = 3
+</code></pre>
+
+</details>
+
 ### `head`
 Get the first element of a list. Yields a runtime error if the list is empty.
 
@@ -16,6 +26,16 @@ Get the first element of a list. Yields a runtime error if the list is empty.
 fn head<A>(xs: List<A>) -> A
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=head%28%5B3%2C%202%2C%201%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> head([3, 2, 1])
+
+    = 3
+</code></pre>
+
+</details>
+
 ### `tail`
 Get everything but the first element of a list. Yields a runtime error if the list is empty.
 
@@ -23,6 +43,16 @@ Get everything but the first element of a list. Yields a runtime error if the li
 fn tail<A>(xs: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=tail%28%5B3%2C%202%2C%201%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> tail([3, 2, 1])
+
+    = [2, 1]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `cons`
 Prepend an element to a list.
 
@@ -30,6 +60,16 @@ Prepend an element to a list.
 fn cons<A>(x: A, xs: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=cons%2877%2C%20%5B3%2C%202%2C%201%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> cons(77, [3, 2, 1])
+
+    = [77, 3, 2, 1]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `cons_end`
 Append an element to the end of a list.
 
@@ -37,6 +77,16 @@ Append an element to the end of a list.
 fn cons_end<A>(x: A, xs: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=cons%5Fend%2877%2C%20%5B3%2C%202%2C%201%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> cons_end(77, [3, 2, 1])
+
+    = [3, 2, 1, 77]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `is_empty`
 Check if a list is empty.
 
@@ -44,6 +94,21 @@ Check if a list is empty.
 fn is_empty<A>(xs: List<A>) -> Bool
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=is%5Fempty%28%5B3%2C%202%2C%201%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> is_empty([3, 2, 1])
+
+    = false    [Bool]
+</code></pre>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=is%5Fempty%28%5B%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> is_empty([])
+
+    = true    [Bool]
+</code></pre>
+
+</details>
+
 ### `concat`
 Concatenate two lists.
 
@@ -51,6 +116,16 @@ Concatenate two lists.
 fn concat<A>(xs1: List<A>, xs2: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=concat%28%5B3%2C%202%2C%201%5D%2C%20%5B10%2C%2011%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> concat([3, 2, 1], [10, 11])
+
+    = [3, 2, 1, 10, 11]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `take`
 Get the first `n` elements of a list.
 
@@ -58,6 +133,16 @@ Get the first `n` elements of a list.
 fn take<A>(n: Scalar, xs: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=take%282%2C%20%5B3%2C%202%2C%201%2C%200%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> take(2, [3, 2, 1, 0])
+
+    = [3, 2]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `drop`
 Get everything but the first `n` elements of a list.
 
@@ -65,6 +150,16 @@ Get everything but the first `n` elements of a list.
 fn drop<A>(n: Scalar, xs: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=drop%282%2C%20%5B3%2C%202%2C%201%2C%200%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> drop(2, [3, 2, 1, 0])
+
+    = [1, 0]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `element_at`
 Get the element at index `i` in a list.
 
@@ -72,6 +167,16 @@ Get the element at index `i` in a list.
 fn element_at<A>(i: Scalar, xs: List<A>) -> A
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=element%5Fat%282%2C%20%5B3%2C%202%2C%201%2C%200%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> element_at(2, [3, 2, 1, 0])
+
+    = 1
+</code></pre>
+
+</details>
+
 ### `range`
 Generate a range of integer numbers from `start` to `end` (inclusive).
 
@@ -79,6 +184,16 @@ Generate a range of integer numbers from `start` to `end` (inclusive).
 fn range(start: Scalar, end: Scalar) -> List<Scalar>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=range%282%2C%2012%29')""></button></div><code class="language-nbt hljs numbat">>>> range(2, 12)
+
+    = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `reverse`
 Reverse the order of a list.
 
@@ -86,6 +201,16 @@ Reverse the order of a list.
 fn reverse<A>(xs: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=reverse%28%5B3%2C%202%2C%201%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> reverse([3, 2, 1])
+
+    = [1, 2, 3]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `map`
 Generate a new list by applying a function to each element of the input list.
 
@@ -93,6 +218,17 @@ Generate a new list by applying a function to each element of the input list.
 fn map<A, B>(f: Fn[(A) -> B], xs: List<A>) -> List<B>
 ```
 
+<details>
+<summary>Examples</summary>
+
+Square all elements of a list.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=map%28sqr%2C%20%5B3%2C%202%2C%201%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> map(sqr, [3, 2, 1])
+
+    = [9, 4, 1]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `filter`
 Filter a list by a predicate.
 
@@ -100,6 +236,16 @@ Filter a list by a predicate.
 fn filter<A>(p: Fn[(A) -> Bool], xs: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=filter%28is%5Ffinite%2C%20%5B0%2C%201e10%2C%20NaN%2C%20%2Dinf%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> filter(is_finite, [0, 1e10, NaN, -inf])
+
+    = [0, 10_000_000_000]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `foldl`
 Fold a function over a list.
 
@@ -107,6 +253,17 @@ Fold a function over a list.
 fn foldl<A, B>(f: Fn[(A, B) -> A], acc: A, xs: List<B>) -> A
 ```
 
+<details>
+<summary>Examples</summary>
+
+Join a list of strings by folding.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=foldl%28str%5Fappend%2C%20%22%22%2C%20%5B%22Num%22%2C%20%22bat%22%2C%20%22%21%22%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> foldl(str_append, "", ["Num", "bat", "!"])
+
+    = "Numbat!"    [String]
+</code></pre>
+
+</details>
+
 ### `sort_by_key`
 Sort a list of elements, using the given key function that maps the element to a quantity.
 
@@ -114,6 +271,18 @@ Sort a list of elements, using the given key function that maps the element to a
 fn sort_by_key<A, D: Dim>(key: Fn[(A) -> D], xs: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+Sort by last digit.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=fn%20last%5Fdigit%28x%29%20%3D%20mod%28x%2C%2010%29%0Asort%5Fby%5Fkey%28last%5Fdigit%2C%20%5B701%2C%20313%2C%209999%2C%204%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> fn last_digit(x) = mod(x, 10)
+sort_by_key(last_digit, [701, 313, 9999, 4])
+
+    = [701, 313, 4, 9999]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `sort`
 Sort a list of quantities.
 
@@ -121,6 +290,16 @@ Sort a list of quantities.
 fn sort<D: Dim>(xs: List<D>) -> List<D>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=sort%28%5B3%2C%202%2C%207%2C%208%2C%20%2D4%2C%200%2C%20%2D5%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> sort([3, 2, 7, 8, -4, 0, -5])
+
+    = [-5, -4, 0, 2, 3, 7, 8]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `intersperse`
 Add an element between each pair of elements in a list.
 
@@ -128,6 +307,16 @@ Add an element between each pair of elements in a list.
 fn intersperse<A>(sep: A, xs: List<A>) -> List<A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=intersperse%280%2C%20%5B1%2C%201%2C%201%2C%201%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> intersperse(0, [1, 1, 1, 1])
+
+    = [1, 0, 1, 0, 1, 0, 1]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ### `sum`
 Sum all elements of a list.
 
@@ -135,6 +324,16 @@ Sum all elements of a list.
 fn sum<D: Dim>(xs: List<D>) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=sum%28%5B3%20m%2C%20200%20cm%2C%201000%20mm%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> sum([3 m, 200 cm, 1000 mm])
+
+    = 6 m    [Length]
+</code></pre>
+
+</details>
+
 ### `linspace`
 Generate a list of `n_steps` evenly spaced numbers from `start` to `end` (inclusive).
 
@@ -142,6 +341,16 @@ Generate a list of `n_steps` evenly spaced numbers from `start` to `end` (inclus
 fn linspace<D: Dim>(start: D, end: D, n_steps: Scalar) -> List<D>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=linspace%28%2D5%20m%2C%205%20m%2C%2011%29')""></button></div><code class="language-nbt hljs numbat">>>> linspace(-5 m, 5 m, 11)
+
+    = [-5 m, -4 m, -3 m, -2 m, -1 m, 0 m, 1 m, 2 m, 3 m, 4 m, 5 m]    [List<Length>]
+</code></pre>
+
+</details>
+
 ### `join`
 Convert a list of strings into a single string by concatenating them with a separator.
 
@@ -149,6 +358,16 @@ Convert a list of strings into a single string by concatenating them with a sepa
 fn join(xs: List<String>, sep: String) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=join%28%5B%22snake%22%2C%20%22case%22%5D%2C%20%22%5F%22%29')""></button></div><code class="language-nbt hljs numbat">>>> join(["snake", "case"], "_")
+
+    = "snake_case"    [String]
+</code></pre>
+
+</details>
+
 ### `split`
 Split a string into a list of strings using a separator.
 
@@ -156,3 +375,13 @@ Split a string into a list of strings using a separator.
 fn split(input: String, separator: String) -> List<String>
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=split%28%22Numbat%20is%20a%20statically%20typed%20programming%20language%2E%22%2C%20%22%20%22%29')""></button></div><code class="language-nbt hljs numbat">>>> split("Numbat is a statically typed programming language.", " ")
+
+    = ["Numbat", "is", "a", "statically", "typed", "programming", "language."]    [List<String>]
+</code></pre>
+
+</details>
+

+ 403 - 7
book/src/list-functions-math.md

@@ -13,6 +13,16 @@ Return the input value.
 fn id<A>(x: A) -> A
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=id%288%20kg%29')""></button></div><code class="language-nbt hljs numbat">>>> id(8 kg)
+
+    = 8 kg    [Mass]
+</code></pre>
+
+</details>
+
 ### `abs` (Absolute value)
 Return the absolute value \\( |x| \\) of the input. This works for quantities, too: `abs(-5 m) = 5 m`.
 More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.abs).
@@ -21,6 +31,16 @@ More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.
 fn abs<T: Dim>(x: T) -> T
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=abs%28%2D22%2E2%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> abs(-22.2 m)
+
+    = 22.2 m    [Length]
+</code></pre>
+
+</details>
+
 ### `sqrt` (Square root)
 Return the square root \\( \sqrt{x} \\) of the input: `sqrt(121 m^2) = 11 m`.
 More information [here](https://en.wikipedia.org/wiki/Square_root).
@@ -29,6 +49,16 @@ More information [here](https://en.wikipedia.org/wiki/Square_root).
 fn sqrt<D: Dim>(x: D^2) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=sqrt%284%20are%29%20%2D%3E%20m')""></button></div><code class="language-nbt hljs numbat">>>> sqrt(4 are) -> m
+
+    = 20 m    [Length]
+</code></pre>
+
+</details>
+
 ### `cbrt` (Cube root)
 Return the cube root \\( \sqrt[3]{x} \\) of the input: `cbrt(8 m^3) = 2 m`.
 More information [here](https://en.wikipedia.org/wiki/Cube_root).
@@ -37,6 +67,16 @@ More information [here](https://en.wikipedia.org/wiki/Cube_root).
 fn cbrt<D: Dim>(x: D^3) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=cbrt%288%20L%29%20%2D%3E%20cm')""></button></div><code class="language-nbt hljs numbat">>>> cbrt(8 L) -> cm
+
+    = 20.0 cm    [Length]
+</code></pre>
+
+</details>
+
 ### `sqr` (Square function)
 Return the square of the input, \\( x^2 \\): `sqr(5 m) = 25 m^2`.
 
@@ -44,6 +84,16 @@ Return the square of the input, \\( x^2 \\): `sqr(5 m) = 25 m^2`.
 fn sqr<D: Dim>(x: D) -> D^2
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=sqr%287%29')""></button></div><code class="language-nbt hljs numbat">>>> sqr(7)
+
+    = 49
+</code></pre>
+
+</details>
+
 ### `round` (Rounding)
 Round to the nearest integer. If the value is half-way between two integers, round away from \\( 0 \\). See also: `round_in`.
 More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.round).
@@ -52,13 +102,45 @@ More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.
 fn round(x: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=round%285%2E5%29')""></button></div><code class="language-nbt hljs numbat">>>> round(5.5)
+
+    = 6
+</code></pre>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=round%28%2D5%2E5%29')""></button></div><code class="language-nbt hljs numbat">>>> round(-5.5)
+
+    = -6
+</code></pre>
+
+</details>
+
 ### `round_in` (Rounding)
-Round to the nearest multiple of `base`. For example: `round_in(m, 5.3 m) == 5 m`.
+Round to the nearest multiple of `base`.
 
 ```nbt
 fn round_in<D: Dim>(base: D, value: D) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+Round in meters.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=round%5Fin%28m%2C%205%2E3%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> round_in(m, 5.3 m)
+
+    = 5 m    [Length]
+</code></pre>
+
+Round in centimeters.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=round%5Fin%28cm%2C%205%2E3%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> round_in(cm, 5.3 m)
+
+    = 530 cm    [Length]
+</code></pre>
+
+</details>
+
 ### `floor` (Floor function)
 Returns the largest integer less than or equal to \\( x \\). See also: `floor_in`.
 More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.floor).
@@ -67,13 +149,40 @@ More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.
 fn floor(x: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=floor%285%2E5%29')""></button></div><code class="language-nbt hljs numbat">>>> floor(5.5)
+
+    = 5
+</code></pre>
+
+</details>
+
 ### `floor_in` (Floor function)
-Returns the largest integer multiple of `base` less than or equal to `value`. For example: `floor_in(m, 5.7 m) == 5 m`.
+Returns the largest integer multiple of `base` less than or equal to `value`.
 
 ```nbt
 fn floor_in<D: Dim>(base: D, value: D) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+Floor in meters.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=floor%5Fin%28m%2C%205%2E7%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> floor_in(m, 5.7 m)
+
+    = 5 m    [Length]
+</code></pre>
+
+Floor in centimeters.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=floor%5Fin%28cm%2C%205%2E7%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> floor_in(cm, 5.7 m)
+
+    = 570 cm    [Length]
+</code></pre>
+
+</details>
+
 ### `ceil` (Ceil function)
 Returns the smallest integer greater than or equal to \\( x \\). See also: `ceil_in`.
 More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.ceil).
@@ -82,13 +191,40 @@ More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.
 fn ceil(x: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=ceil%285%2E5%29')""></button></div><code class="language-nbt hljs numbat">>>> ceil(5.5)
+
+    = 6
+</code></pre>
+
+</details>
+
 ### `ceil_in` (Ceil function)
-Returns the smallest integer multuple of `base` greater than or equal to `value`. For example: `ceil_in(m, 5.3 m) == 6 m`.
+Returns the smallest integer multiple of `base` greater than or equal to `value`.
 
 ```nbt
 fn ceil_in<D: Dim>(base: D, value: D) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+Ceil in meters.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=ceil%5Fin%28m%2C%205%2E3%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> ceil_in(m, 5.3 m)
+
+    = 6 m    [Length]
+</code></pre>
+
+Ceil in centimeters.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=ceil%5Fin%28cm%2C%205%2E3%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> ceil_in(cm, 5.3 m)
+
+    = 530 cm    [Length]
+</code></pre>
+
+</details>
+
 ### `trunc` (Truncation)
 Returns the integer part of \\( x \\). Non-integer numbers are always truncated towards zero. See also: `trunc_in`.
 More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.trunc).
@@ -97,13 +233,45 @@ More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.
 fn trunc(x: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=trunc%285%2E5%29')""></button></div><code class="language-nbt hljs numbat">>>> trunc(5.5)
+
+    = 5
+</code></pre>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=trunc%28%2D5%2E5%29')""></button></div><code class="language-nbt hljs numbat">>>> trunc(-5.5)
+
+    = -5
+</code></pre>
+
+</details>
+
 ### `trunc_in` (Truncation)
-Truncates to an integer multiple of `base` (towards zero). For example: `trunc_in(m, -5.7 m) == -5 m`.
+Truncates to an integer multiple of `base` (towards zero).
 
 ```nbt
 fn trunc_in<D: Dim>(base: D, value: D) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+Truncate in meters.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=trunc%5Fin%28m%2C%205%2E7%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> trunc_in(m, 5.7 m)
+
+    = 5 m    [Length]
+</code></pre>
+
+Truncate in centimeters.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=trunc%5Fin%28cm%2C%205%2E7%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> trunc_in(cm, 5.7 m)
+
+    = 570 cm    [Length]
+</code></pre>
+
+</details>
+
 ### `mod` (Modulo)
 Calculates the least nonnegative remainder of \\( a (\mod b) \\).
 More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.rem_euclid).
@@ -112,6 +280,16 @@ More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.
 fn mod<T: Dim>(a: T, b: T) -> T
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=mod%2827%2C%205%29')""></button></div><code class="language-nbt hljs numbat">>>> mod(27, 5)
+
+    = 2
+</code></pre>
+
+</details>
+
 ## Transcendental functions
 
 Defined in: `math::transcendental`
@@ -124,6 +302,16 @@ More information [here](https://en.wikipedia.org/wiki/Exponential_function).
 fn exp(x: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=exp%284%29')""></button></div><code class="language-nbt hljs numbat">>>> exp(4)
+
+    = 54.5982
+</code></pre>
+
+</details>
+
 ### `ln` (Natural logarithm)
 The natural logarithm with base \\( e \\).
 More information [here](https://en.wikipedia.org/wiki/Natural_logarithm).
@@ -132,6 +320,16 @@ More information [here](https://en.wikipedia.org/wiki/Natural_logarithm).
 fn ln(x: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=ln%2820%29')""></button></div><code class="language-nbt hljs numbat">>>> ln(20)
+
+    = 2.99573
+</code></pre>
+
+</details>
+
 ### `log` (Natural logarithm)
 The natural logarithm with base \\( e \\).
 More information [here](https://en.wikipedia.org/wiki/Natural_logarithm).
@@ -140,6 +338,16 @@ More information [here](https://en.wikipedia.org/wiki/Natural_logarithm).
 fn log(x: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=log%2820%29')""></button></div><code class="language-nbt hljs numbat">>>> log(20)
+
+    = 2.99573
+</code></pre>
+
+</details>
+
 ### `log10` (Common logarithm)
 The common logarithm with base \\( 10 \\).
 More information [here](https://en.wikipedia.org/wiki/Common_logarithm).
@@ -148,6 +356,16 @@ More information [here](https://en.wikipedia.org/wiki/Common_logarithm).
 fn log10(x: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=log10%28100%29')""></button></div><code class="language-nbt hljs numbat">>>> log10(100)
+
+    = 2
+</code></pre>
+
+</details>
+
 ### `log2` (Binary logarithm)
 The binary logarithm with base \\( 2 \\).
 More information [here](https://en.wikipedia.org/wiki/Binary_logarithm).
@@ -156,6 +374,16 @@ More information [here](https://en.wikipedia.org/wiki/Binary_logarithm).
 fn log2(x: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=log2%28256%29')""></button></div><code class="language-nbt hljs numbat">>>> log2(256)
+
+    = 8
+</code></pre>
+
+</details>
+
 ### `gamma` (Gamma function)
 The gamma function, \\( \Gamma(x) \\).
 More information [here](https://en.wikipedia.org/wiki/Gamma_function).
@@ -264,27 +492,57 @@ fn atanh(x: Scalar) -> Scalar
 Defined in: `math::statistics`
 
 ### `maximum` (Maxmimum)
-Get the largest element of a list: `maximum([30 cm, 2 m]) = 2 m`.
+Get the largest element of a list.
 
 ```nbt
 fn maximum<D: Dim>(xs: List<D>) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=maximum%28%5B30%20cm%2C%202%20m%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> maximum([30 cm, 2 m])
+
+    = 2 m    [Length]
+</code></pre>
+
+</details>
+
 ### `minimum` (Minimum)
-Get the smallest element of a list: `minimum([30 cm, 2 m]) = 30 cm`.
+Get the smallest element of a list.
 
 ```nbt
 fn minimum<D: Dim>(xs: List<D>) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=minimum%28%5B30%20cm%2C%202%20m%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> minimum([30 cm, 2 m])
+
+    = 30 cm    [Length]
+</code></pre>
+
+</details>
+
 ### `mean` (Arithmetic mean)
-Calculate the arithmetic mean of a list of quantities: `mean([1 m, 2 m, 300 cm]) = 2 m`.
+Calculate the arithmetic mean of a list of quantities.
 More information [here](https://en.wikipedia.org/wiki/Arithmetic_mean).
 
 ```nbt
 fn mean<D: Dim>(xs: List<D>) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=mean%28%5B1%20m%2C%202%20m%2C%20300%20cm%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> mean([1 m, 2 m, 300 cm])
+
+    = 2 m    [Length]
+</code></pre>
+
+</details>
+
 ### `variance` (Variance)
 Calculate the population variance of a list of quantities.
 More information [here](https://en.wikipedia.org/wiki/Variance).
@@ -293,6 +551,16 @@ More information [here](https://en.wikipedia.org/wiki/Variance).
 fn variance<D: Dim>(xs: List<D>) -> D^2
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=variance%28%5B1%20m%2C%202%20m%2C%20300%20cm%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> variance([1 m, 2 m, 300 cm])
+
+    = 0.666667 m²    [Area]
+</code></pre>
+
+</details>
+
 ### `stdev` (Standard deviation)
 Calculate the population standard deviation of a list of quantities.
 More information [here](https://en.wikipedia.org/wiki/Standard_deviation).
@@ -301,6 +569,16 @@ More information [here](https://en.wikipedia.org/wiki/Standard_deviation).
 fn stdev<D: Dim>(xs: List<D>) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=stdev%28%5B1%20m%2C%202%20m%2C%20300%20cm%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> stdev([1 m, 2 m, 300 cm])
+
+    = 0.816497 m    [Length]
+</code></pre>
+
+</details>
+
 ### `median` (Median)
 Calculate the median of a list of quantities.
 More information [here](https://en.wikipedia.org/wiki/Median).
@@ -309,6 +587,16 @@ More information [here](https://en.wikipedia.org/wiki/Median).
 fn median<D: Dim>(xs: List<D>) -> D
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=median%28%5B1%20m%2C%202%20m%2C%20400%20cm%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> median([1 m, 2 m, 400 cm])
+
+    = 2 m    [Length]
+</code></pre>
+
+</details>
+
 ## Random sampling, distributions
 
 Defined in: `core::random`, `math::distributions`
@@ -413,6 +701,16 @@ More information [here](https://en.wikipedia.org/wiki/Greatest_common_divisor).
 fn gcd(a: Scalar, b: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=gcd%2860%2C%2042%29')""></button></div><code class="language-nbt hljs numbat">>>> gcd(60, 42)
+
+    = 6
+</code></pre>
+
+</details>
+
 ### `lcm` (Least common multiple)
 The smallest positive integer that is divisible by both \\( a \\) and \\( b \\).
 More information [here](https://en.wikipedia.org/wiki/Least_common_multiple).
@@ -421,6 +719,16 @@ More information [here](https://en.wikipedia.org/wiki/Least_common_multiple).
 fn lcm(a: Scalar, b: Scalar) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=lcm%2814%2C%204%29')""></button></div><code class="language-nbt hljs numbat">>>> lcm(14, 4)
+
+    = 28
+</code></pre>
+
+</details>
+
 ## Numerical methods
 
 Defined in: `numerics::diff`, `numerics::solve`, `numerics::fixed_point`
@@ -433,6 +741,26 @@ More information [here](https://en.wikipedia.org/wiki/Numerical_differentiation)
 fn diff<X: Dim, Y: Dim>(f: Fn[(X) -> Y], x: X) -> Y / X
 ```
 
+<details>
+<summary>Examples</summary>
+
+Compute the derivative of \\( f(x) = x² -x -1 \\) at \\( x=1 \\).
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20numerics%3A%3Adiff%0Afn%20polynomial%28x%29%20%3D%20x%C2%B2%20%2D%20x%20%2D%201%0Adiff%28polynomial%2C%201%29')""></button></div><code class="language-nbt hljs numbat">>>> fn polynomial(x) = x² - x - 1
+diff(polynomial, 1)
+
+    = 1.0
+</code></pre>
+
+Compute the free fall velocity after \\( t=2 s \\).
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20numerics%3A%3Adiff%0Afn%20distance%28t%29%20%3D%200%2E5%20g0%20t%C2%B2%0Afn%20velocity%28t%29%20%3D%20diff%28distance%2C%20t%29%0Avelocity%282%20s%29')""></button></div><code class="language-nbt hljs numbat">>>> fn distance(t) = 0.5 g0 t²
+fn velocity(t) = diff(distance, t)
+velocity(2 s)
+
+    = 19.6133 m/s    [Velocity]
+</code></pre>
+
+</details>
+
 ### `root_bisect` (Bisection method)
 Find the root of the function \\( f \\) in the interval \\( [x_1, x_2] \\) using the bisection method. The function \\( f \\) must be continuous and \\( f(x_1) \cdot f(x_2) < 0 \\).
 More information [here](https://en.wikipedia.org/wiki/Bisection_method).
@@ -441,6 +769,18 @@ More information [here](https://en.wikipedia.org/wiki/Bisection_method).
 fn root_bisect<X: Dim, Y: Dim>(f: Fn[(X) -> Y], x1: X, x2: X, x_tol: X, y_tol: Y) -> X
 ```
 
+<details>
+<summary>Examples</summary>
+
+Find the root of \\( f(x) = x² +x -2 \\) in the interval \\( [0, 100] \\).
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20numerics%3A%3Asolve%0Afn%20f%28x%29%20%3D%20x%C2%B2%20%2Bx%20%2D2%0Aroot%5Fbisect%28f%2C%200%2C%20100%2C%200%2E01%2C%200%2E01%29')""></button></div><code class="language-nbt hljs numbat">>>> fn f(x) = x² +x -2
+root_bisect(f, 0, 100, 0.01, 0.01)
+
+    = 1.00098
+</code></pre>
+
+</details>
+
 ### `root_newton` (Newton's method)
 Find the root of the function \\( f(x) \\) and its derivative \\( f'(x) \\) using Newton's method.
 More information [here](https://en.wikipedia.org/wiki/Newton%27s_method).
@@ -449,6 +789,19 @@ More information [here](https://en.wikipedia.org/wiki/Newton%27s_method).
 fn root_newton<X: Dim, Y: Dim>(f: Fn[(X) -> Y], f_prime: Fn[(X) -> Y / X], x0: X, y_tol: Y) -> X
 ```
 
+<details>
+<summary>Examples</summary>
+
+Find a root of \\( f(x) = x² -3x +2 \\) using Newton's method.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20numerics%3A%3Asolve%0Afn%20f%28x%29%20%3D%20x%C2%B2%20%2D3x%20%2B2%0Afn%20f%5Fprime%28x%29%20%3D%202x%20%2D3%0Aroot%5Fnewton%28f%2C%20f%5Fprime%2C%200%20%2C%200%2E01%29')""></button></div><code class="language-nbt hljs numbat">>>> fn f(x) = x² -3x +2
+fn f_prime(x) = 2x -3
+root_newton(f, f_prime, 0 , 0.01)
+
+    = 0.996078
+</code></pre>
+
+</details>
+
 ### `fixed_point` (Fixed-point iteration)
 Compute the approximate fixed point of a function \\( f: X \rightarrow X \\) starting from \\( x_0 \\), until \\( |f(x) - x| < ε \\).
 More information [here](https://en.wikipedia.org/wiki/Fixed-point_iteration).
@@ -457,6 +810,18 @@ More information [here](https://en.wikipedia.org/wiki/Fixed-point_iteration).
 fn fixed_point<X: Dim>(f: Fn[(X) -> X], x0: X, ε: X) -> X
 ```
 
+<details>
+<summary>Examples</summary>
+
+Compute the fixed poin of \\( f(x) = x/2 -1 \\).
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20numerics%3A%3Afixed%5Fpoint%0Afn%20function%28x%29%20%3D%20x%2F2%20%2D%201%0Afixed%5Fpoint%28function%2C%200%2C%200%2E01%29')""></button></div><code class="language-nbt hljs numbat">>>> fn function(x) = x/2 - 1
+fixed_point(function, 0, 0.01)
+
+    = -1.99219
+</code></pre>
+
+</details>
+
 ## Geometry
 
 Defined in: `math::geometry`
@@ -468,6 +833,16 @@ The length of the hypotenuse of a right-angled triangle \\( \sqrt{x^2+y^2} \\).
 fn hypot2<T: Dim>(x: T, y: T) -> T
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=hypot2%283%20m%2C%204%20m%29')""></button></div><code class="language-nbt hljs numbat">>>> hypot2(3 m, 4 m)
+
+    = 5 m    [Length]
+</code></pre>
+
+</details>
+
 ### `hypot3`
 The Euclidean norm of a 3D vector \\( \sqrt{x^2+y^2+z^2} \\).
 
@@ -475,6 +850,16 @@ The Euclidean norm of a 3D vector \\( \sqrt{x^2+y^2+z^2} \\).
 fn hypot3<T: Dim>(x: T, y: T, z: T) -> T
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=hypot3%288%2C%209%2C%2012%29')""></button></div><code class="language-nbt hljs numbat">>>> hypot3(8, 9, 12)
+
+    = 17
+</code></pre>
+
+</details>
+
 ### `circle_area`
 The area of a circle, \\( \pi r^2 \\).
 
@@ -515,6 +900,17 @@ More information [here](https://en.wikipedia.org/wiki/Quadratic_equation).
 fn quadratic_equation<A: Dim, B: Dim>(a: A, b: B, c: B^2 / A) -> List<B / A>
 ```
 
+<details>
+<summary>Examples</summary>
+
+Solve the equation \\( 2x² -x -1 = 0 \\)
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20extra%3A%3Aalgebra%0Aquadratic%5Fequation%282%2C%20%2D1%2C%20%2D1%29')""></button></div><code class="language-nbt hljs numbat">>>> quadratic_equation(2, -1, -1)
+
+    = [1, -0.5]    [List<Scalar>]
+</code></pre>
+
+</details>
+
 ## Trigonometry (extra)
 
 Defined in: `math::trigonometry_extra`

+ 221 - 5
book/src/list-functions-other.md

@@ -25,6 +25,21 @@ More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.
 fn is_nan<T: Dim>(n: T) -> Bool
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=is%5Fnan%2837%29')""></button></div><code class="language-nbt hljs numbat">>>> is_nan(37)
+
+    = false    [Bool]
+</code></pre>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=is%5Fnan%28NaN%29')""></button></div><code class="language-nbt hljs numbat">>>> is_nan(NaN)
+
+    = true    [Bool]
+</code></pre>
+
+</details>
+
 ### `is_infinite`
 Returns true if the input is positive infinity or negative infinity.
 More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite).
@@ -33,6 +48,21 @@ More information [here](https://doc.rust-lang.org/std/primitive.f64.html#method.
 fn is_infinite<T: Dim>(n: T) -> Bool
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=is%5Finfinite%2837%29')""></button></div><code class="language-nbt hljs numbat">>>> is_infinite(37)
+
+    = false    [Bool]
+</code></pre>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=is%5Finfinite%28%2Dinf%29')""></button></div><code class="language-nbt hljs numbat">>>> is_infinite(-inf)
+
+    = true    [Bool]
+</code></pre>
+
+</details>
+
 ### `is_finite`
 Returns true if the input is neither infinite nor `NaN`.
 
@@ -40,6 +70,21 @@ Returns true if the input is neither infinite nor `NaN`.
 fn is_finite<T: Dim>(n: T) -> Bool
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=is%5Ffinite%2837%29')""></button></div><code class="language-nbt hljs numbat">>>> is_finite(37)
+
+    = true    [Bool]
+</code></pre>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=is%5Ffinite%28%2Dinf%29')""></button></div><code class="language-nbt hljs numbat">>>> is_finite(-inf)
+
+    = false    [Bool]
+</code></pre>
+
+</details>
+
 ## Quantities
 
 Defined in: `core::quantities`
@@ -51,6 +96,16 @@ Extract the unit of a quantity (the `km/h` in `20 km/h`). This can be useful in
 fn unit_of<T: Dim>(x: T) -> T
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=unit%5Fof%2820%20km%2Fh%29')""></button></div><code class="language-nbt hljs numbat">>>> unit_of(20 km/h)
+
+    = 1 km/h    [Velocity]
+</code></pre>
+
+</details>
+
 ### `value_of`
 Extract the plain value of a quantity (the `20` in `20 km/h`). This can be useful in generic code, but should generally be avoided otherwise.
 
@@ -58,17 +113,44 @@ Extract the plain value of a quantity (the `20` in `20 km/h`). This can be usefu
 fn value_of<T: Dim>(x: T) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=value%5Fof%2820%20km%2Fh%29')""></button></div><code class="language-nbt hljs numbat">>>> value_of(20 km/h)
+
+    = 20
+</code></pre>
+
+</details>
+
 ## Chemical elements
 
 Defined in: `chemistry::elements`
 
 ### `element` (Chemical element)
-Get properties of a chemical element by its symbol or name (case-insensitive). For example: `element("H")` or `element("hydrogen")`.
+Get properties of a chemical element by its symbol or name (case-insensitive).
 
 ```nbt
 fn element(pattern: String) -> ChemicalElement
 ```
 
+<details>
+<summary>Examples</summary>
+
+Get the entire element struct for hydrogen.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=element%28%22H%22%29')""></button></div><code class="language-nbt hljs numbat">>>> element("H")
+
+    = ChemicalElement { symbol: "H", name: "Hydrogen", atomic_number: 1, group: 1, group_name: "Alkali metals", period: 1, melting_point: 13.99 K, boiling_point: 20.271 K, density: 0.00008988 g/cm³, electron_affinity: 0.754 eV, ionization_energy: 13.598 eV, vaporization_heat: 0.904 kJ/mol }    [ChemicalElement]
+</code></pre>
+
+Get the ionization energy of hydrogen.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=element%28%22hydrogen%22%29%2Eionization%5Fenergy')""></button></div><code class="language-nbt hljs numbat">>>> element("hydrogen").ionization_energy
+
+    = 13.598 eV    [Energy or Torque]
+</code></pre>
+
+</details>
+
 ## Mixed unit conversion
 
 Defined in: `units::mixed`
@@ -81,6 +163,16 @@ More information [here](https://en.wikipedia.org/wiki/Sexagesimal_degree).
 fn DMS(alpha: Angle) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=46%2E5858%C2%B0%20%2D%3E%20DMS')""></button></div><code class="language-nbt hljs numbat">>>> 46.5858° -> DMS
+
+    = "46° 35′ 9″"    [String]
+</code></pre>
+
+</details>
+
 ### `DM` (Degrees, decimal minutes)
 Convert an angle to a mixed degrees and decimal minutes representation.
 More information [here](https://en.wikipedia.org/wiki/Decimal_degrees).
@@ -89,6 +181,16 @@ More information [here](https://en.wikipedia.org/wiki/Decimal_degrees).
 fn DM(alpha: Angle) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=46%2E5858%C2%B0%20%2D%3E%20DM')""></button></div><code class="language-nbt hljs numbat">>>> 46.5858° -> DM
+
+    = "46° 35.148′"    [String]
+</code></pre>
+
+</details>
+
 ### `feet_and_inches` (Feet and inches)
 Convert a length to a mixed feet and inches representation.
 More information [here](https://en.wikipedia.org/wiki/Foot_(unit)).
@@ -97,6 +199,16 @@ More information [here](https://en.wikipedia.org/wiki/Foot_(unit)).
 fn feet_and_inches(length: Length) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=180%20cm%20%2D%3E%20feet%5Fand%5Finches')""></button></div><code class="language-nbt hljs numbat">>>> 180 cm -> feet_and_inches
+
+    = "5 ft 10.8661 in"    [String]
+</code></pre>
+
+</details>
+
 ### `pounds_and_ounces` (Pounds and ounces)
 Convert a mass to a mixed pounds and ounces representation.
 More information [here](https://en.wikipedia.org/wiki/Pound_(mass)).
@@ -105,6 +217,16 @@ More information [here](https://en.wikipedia.org/wiki/Pound_(mass)).
 fn pounds_and_ounces(mass: Mass) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=1%20kg%20%2D%3E%20pounds%5Fand%5Founces')""></button></div><code class="language-nbt hljs numbat">>>> 1 kg -> pounds_and_ounces
+
+    = "2 lb 3.27396 oz"    [String]
+</code></pre>
+
+</details>
+
 ## Temperature conversion
 
 Defined in: `physics::temperature_conversion`
@@ -117,6 +239,17 @@ More information [here](https://en.wikipedia.org/wiki/Conversion_of_scales_of_te
 fn from_celsius(t_celsius: Scalar) -> Temperature
 ```
 
+<details>
+<summary>Examples</summary>
+
+300 °C in Kelvin.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=from%5Fcelsius%28300%29')""></button></div><code class="language-nbt hljs numbat">>>> from_celsius(300)
+
+    = 573.15 K    [Temperature]
+</code></pre>
+
+</details>
+
 ### `celsius`
 Converts from Kelvin to degree Celcius (°C). This can be used on the right hand side of a conversion operator: `200 K -> celsius`.
 More information [here](https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature).
@@ -125,6 +258,17 @@ More information [here](https://en.wikipedia.org/wiki/Conversion_of_scales_of_te
 fn celsius(t_kelvin: Temperature) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+300 K in degree Celsius.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=300K%20%2D%3E%20celsius')""></button></div><code class="language-nbt hljs numbat">>>> 300K -> celsius
+
+    = 26.85
+</code></pre>
+
+</details>
+
 ### `from_fahrenheit`
 Converts from degree Fahrenheit (°F) to Kelvin.
 More information [here](https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature).
@@ -133,6 +277,17 @@ More information [here](https://en.wikipedia.org/wiki/Conversion_of_scales_of_te
 fn from_fahrenheit(t_fahrenheit: Scalar) -> Temperature
 ```
 
+<details>
+<summary>Examples</summary>
+
+300 °F in Kelvin.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=from%5Ffahrenheit%28300%29')""></button></div><code class="language-nbt hljs numbat">>>> from_fahrenheit(300)
+
+    = 422.039 K    [Temperature]
+</code></pre>
+
+</details>
+
 ### `fahrenheit`
 Converts from Kelvin to degree Fahrenheit (°F). This can be used on the right hand side of a conversion operator: `200 K -> fahrenheit`.
 More information [here](https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature).
@@ -141,6 +296,17 @@ More information [here](https://en.wikipedia.org/wiki/Conversion_of_scales_of_te
 fn fahrenheit(t_kelvin: Temperature) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+300 K in degree Fahrenheit.
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=300K%20%2D%3E%20fahrenheit')""></button></div><code class="language-nbt hljs numbat">>>> 300K -> fahrenheit
+
+    = 80.33
+</code></pre>
+
+</details>
+
 ## Color format conversion
 
 Defined in: `extra::color`
@@ -152,31 +318,81 @@ Create a `Color` from RGB (red, green, blue) values in the range \\( [0, 256) \\
 fn rgb(red: Scalar, green: Scalar, blue: Scalar) -> Color
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20extra%3A%3Acolor%0Argb%28125%2C%20128%2C%20218%29')""></button></div><code class="language-nbt hljs numbat">>>> rgb(125, 128, 218)
+
+    = Color { red: 125, green: 128, blue: 218 }    [Color]
+</code></pre>
+
+</details>
+
 ### `color`
-Create a `Color` from a (hexadecimal) value, e.g. `color(0xff7700)`.
+Create a `Color` from a (hexadecimal) value.
 
 ```nbt
 fn color(rgb_hex: Scalar) -> Color
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20extra%3A%3Acolor%0Acolor%280xff7700%29')""></button></div><code class="language-nbt hljs numbat">>>> color(0xff7700)
+
+    = Color { red: 255, green: 119, blue: 0 }    [Color]
+</code></pre>
+
+</details>
+
 ### `color_rgb`
-Convert a color to its RGB representation, e.g. `cyan -> color_rgb`.
+Convert a color to its RGB representation.
 
 ```nbt
 fn color_rgb(color: Color) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20extra%3A%3Acolor%0Acyan%20%2D%3E%20color%5Frgb')""></button></div><code class="language-nbt hljs numbat">>>> cyan -> color_rgb
+
+    = "rgb(0, 255, 255)"    [String]
+</code></pre>
+
+</details>
+
 ### `color_rgb_float`
-Convert a color to its RGB floating point representation, e.g. `cyan -> color_rgb_float`.
+Convert a color to its RGB floating point representation.
 
 ```nbt
 fn color_rgb_float(color: Color) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20extra%3A%3Acolor%0Acyan%20%2D%3E%20color%5Frgb%5Ffloat')""></button></div><code class="language-nbt hljs numbat">>>> cyan -> color_rgb_float
+
+    = "rgb(0.000, 1.000, 1.000)"    [String]
+</code></pre>
+
+</details>
+
 ### `color_hex`
-Convert a color to its hexadecimal representation, e.g. `rgb(225, 36, 143) -> color_hex`.
+Convert a color to its hexadecimal representation.
 
 ```nbt
 fn color_hex(color: Color) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=use%20extra%3A%3Acolor%0Argb%28225%2C%2036%2C%20143%29%20%2D%3E%20color%5Fhex')""></button></div><code class="language-nbt hljs numbat">>>> rgb(225, 36, 143) -> color_hex
+
+    = "#e1248f"    [String]
+</code></pre>
+
+</details>
+

+ 166 - 6
book/src/list-functions-strings.md

@@ -9,6 +9,16 @@ The length of a string.
 fn str_length(s: String) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=str%5Flength%28%22Numbat%22%29')""></button></div><code class="language-nbt hljs numbat">>>> str_length("Numbat")
+
+    = 6
+</code></pre>
+
+</details>
+
 ### `str_slice`
 Subslice of a string.
 
@@ -16,20 +26,50 @@ Subslice of a string.
 fn str_slice(s: String, start: Scalar, end: Scalar) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=str%5Fslice%28%22Numbat%22%2C%203%2C%206%29')""></button></div><code class="language-nbt hljs numbat">>>> str_slice("Numbat", 3, 6)
+
+    = "bat"    [String]
+</code></pre>
+
+</details>
+
 ### `chr`
-Get a single-character string from a Unicode code point. Example: `0x2764 -> chr`.
+Get a single-character string from a Unicode code point.
 
 ```nbt
 fn chr(n: Scalar) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=0x2764%20%2D%3E%20chr')""></button></div><code class="language-nbt hljs numbat">>>> 0x2764 -> chr
+
+    = "❤"    [String]
+</code></pre>
+
+</details>
+
 ### `ord`
-Get the Unicode code point of the first character in a string. Example: `"❤" -> ord`.
+Get the Unicode code point of the first character in a string.
 
 ```nbt
 fn ord(s: String) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=%22%E2%9D%A4%22%20%2D%3E%20ord')""></button></div><code class="language-nbt hljs numbat">>>> "❤" -> ord
+
+    = 10084
+</code></pre>
+
+</details>
+
 ### `lowercase`
 Convert a string to lowercase.
 
@@ -37,6 +77,16 @@ Convert a string to lowercase.
 fn lowercase(s: String) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=lowercase%28%22Numbat%22%29')""></button></div><code class="language-nbt hljs numbat">>>> lowercase("Numbat")
+
+    = "numbat"    [String]
+</code></pre>
+
+</details>
+
 ### `uppercase`
 Convert a string to uppercase.
 
@@ -44,6 +94,16 @@ Convert a string to uppercase.
 fn uppercase(s: String) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=uppercase%28%22Numbat%22%29')""></button></div><code class="language-nbt hljs numbat">>>> uppercase("Numbat")
+
+    = "NUMBAT"    [String]
+</code></pre>
+
+</details>
+
 ### `str_append`
 Concatenate two strings.
 
@@ -51,6 +111,16 @@ Concatenate two strings.
 fn str_append(a: String, b: String) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=str%5Fappend%28%22Numbat%22%2C%20%22%21%22%29')""></button></div><code class="language-nbt hljs numbat">>>> str_append("Numbat", "!")
+
+    = "Numbat!"    [String]
+</code></pre>
+
+</details>
+
 ### `str_find`
 Find the first occurrence of a substring in a string.
 
@@ -58,6 +128,16 @@ Find the first occurrence of a substring in a string.
 fn str_find(haystack: String, needle: String) -> Scalar
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=str%5Ffind%28%22Numbat%20is%20a%20statically%20typed%20programming%20language%2E%22%2C%20%22typed%22%29')""></button></div><code class="language-nbt hljs numbat">>>> str_find("Numbat is a statically typed programming language.", "typed")
+
+    = 23
+</code></pre>
+
+</details>
+
 ### `str_contains`
 Check if a string contains a substring.
 
@@ -65,6 +145,16 @@ Check if a string contains a substring.
 fn str_contains(haystack: String, needle: String) -> Bool
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=str%5Fcontains%28%22Numbat%20is%20a%20statically%20typed%20programming%20language%2E%22%2C%20%22typed%22%29')""></button></div><code class="language-nbt hljs numbat">>>> str_contains("Numbat is a statically typed programming language.", "typed")
+
+    = true    [Bool]
+</code></pre>
+
+</details>
+
 ### `str_replace`
 Replace all occurrences of a substring in a string.
 
@@ -72,6 +162,16 @@ Replace all occurrences of a substring in a string.
 fn str_replace(s: String, pattern: String, replacement: String) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=str%5Freplace%28%22Numbat%20is%20a%20statically%20typed%20programming%20language%2E%22%2C%20%22statically%20typed%20programming%20language%22%2C%20%22scientific%20calculator%22%29')""></button></div><code class="language-nbt hljs numbat">>>> str_replace("Numbat is a statically typed programming language.", "statically typed programming language", "scientific calculator")
+
+    = "Numbat is a scientific calculator."    [String]
+</code></pre>
+
+</details>
+
 ### `str_repeat`
 Repeat the input string `n` times.
 
@@ -79,27 +179,67 @@ Repeat the input string `n` times.
 fn str_repeat(a: String, n: Scalar) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=str%5Frepeat%28%22abc%22%2C%204%29')""></button></div><code class="language-nbt hljs numbat">>>> str_repeat("abc", 4)
+
+    = "abcabcabcabc"    [String]
+</code></pre>
+
+</details>
+
 ### `base`
-Convert a number to the given base. Example: `42 |> base(16)`.
+Convert a number to the given base.
 
 ```nbt
 fn base(b: Scalar, x: Scalar) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=42%20%7C%3E%20base%2816%29')""></button></div><code class="language-nbt hljs numbat">>>> 42 |> base(16)
+
+    = "2a"    [String]
+</code></pre>
+
+</details>
+
 ### `bin`
-Get a binary representation of a number. Example: `42 -> bin`.
+Get a binary representation of a number.
 
 ```nbt
 fn bin(x: Scalar) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=42%20%2D%3E%20bin')""></button></div><code class="language-nbt hljs numbat">>>> 42 -> bin
+
+    = "0b101010"    [String]
+</code></pre>
+
+</details>
+
 ### `oct`
-Get an octal representation of a number. Example: `42 -> oct`.
+Get an octal representation of a number.
 
 ```nbt
 fn oct(x: Scalar) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=42%20%2D%3E%20oct')""></button></div><code class="language-nbt hljs numbat">>>> 42 -> oct
+
+    = "0o52"    [String]
+</code></pre>
+
+</details>
+
 ### `dec`
 Get a decimal representation of a number.
 
@@ -107,10 +247,30 @@ Get a decimal representation of a number.
 fn dec(x: Scalar) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=0b111%20%2D%3E%20dec')""></button></div><code class="language-nbt hljs numbat">>>> 0b111 -> dec
+
+    = "7"    [String]
+</code></pre>
+
+</details>
+
 ### `hex`
-Get a hexadecimal representation of a number. Example: `2^31-1 -> hex`.
+Get a hexadecimal representation of a number.
 
 ```nbt
 fn hex(x: Scalar) -> String
 ```
 
+<details>
+<summary>Examples</summary>
+
+<pre><div class="buttons"><button class="fa fa-play play-button" title="Run this code" aria-label="Run this code"  onclick=" window.open('https://numbat.dev/?q=2%5E31%2D1%20%2D%3E%20hex')""></button></div><code class="language-nbt hljs numbat">>>> 2^31-1 -> hex
+
+    = "0x7fffffff"    [String]
+</code></pre>
+
+</details>
+

+ 1 - 0
numbat/Cargo.toml

@@ -49,6 +49,7 @@ glob = "0.3"
 insta = "1.34.0"
 once_cell = "1.19.0"
 criterion = { version = "0.5", features = ["html_reports"] }
+percent-encoding = "2.3.1"
 
 [[bench]]
 name = "prelude"

+ 112 - 20
numbat/examples/inspect.rs

@@ -1,5 +1,9 @@
 use itertools::Itertools;
-use numbat::{module_importer::FileSystemImporter, resolver::CodeSource, Context};
+use numbat::markup::plain_text_format;
+use numbat::module_importer::FileSystemImporter;
+use numbat::resolver::CodeSource;
+use numbat::Context;
+use percent_encoding;
 use std::path::Path;
 
 const AUTO_GENERATED_HINT: &str = "<!-- NOTE! This file is auto-generated -->";
@@ -40,8 +44,8 @@ and — where sensible — units allow for [binary prefixes](https://en.wikipedi
     }
 }
 
-fn inspect_functions_in_module(ctx: &Context, module: String) {
-    for (fn_name, name, signature, description, url, code_source) in ctx.functions() {
+fn inspect_functions_in_module(ctx: &Context, prelude_ctx: &Context, module: String) {
+    for (fn_name, name, signature, description, url, examples, code_source) in ctx.functions() {
         let CodeSource::Module(module_path, _) = code_source else {
             unreachable!();
         };
@@ -57,19 +61,7 @@ fn inspect_functions_in_module(ctx: &Context, module: String) {
         }
 
         if let Some(ref description_raw) = description {
-            let description_raw = description_raw.trim().to_string();
-
-            // Replace $..$ with \\( .. \\) for mdbook.
-            let mut description = String::new();
-            for (i, part) in description_raw.split('$').enumerate() {
-                if i % 2 == 0 {
-                    description.push_str(part);
-                } else {
-                    description.push_str("\\\\( ");
-                    description.push_str(part);
-                    description.push_str(" \\\\)");
-                }
-            }
+            let description = replace_equation_delimiters(description_raw.trim().to_string());
 
             if description.ends_with('.') {
                 println!("{description}");
@@ -86,17 +78,117 @@ fn inspect_functions_in_module(ctx: &Context, module: String) {
         println!("{signature}");
         println!("```");
         println!();
+
+        if !examples.is_empty() {
+            println!("<details>");
+            println!("<summary>Examples</summary>");
+            println!();
+
+            for (example_code, example_description) in examples {
+                let mut example_ctx = prelude_ctx.clone();
+                let extra_import = if !example_ctx
+                    .resolver()
+                    .imported_modules
+                    .contains(&module_path)
+                {
+                    format!("use {}\n", module)
+                } else {
+                    "".into()
+                };
+                let _result = example_ctx
+                    .interpret(&extra_import, CodeSource::Internal)
+                    .unwrap();
+
+                if let Ok((statements, results)) =
+                    example_ctx.interpret(&example_code, CodeSource::Internal)
+                {
+                    //Format the example input
+                    let example_input = format!(">>> {}", example_code);
+
+                    //Encode the example url
+                    let url_code = extra_import + &example_code;
+                    let example_url = format!(
+                        "https://numbat.dev/?q={}",
+                        percent_encoding::utf8_percent_encode(
+                            &url_code,
+                            percent_encoding::NON_ALPHANUMERIC
+                        )
+                    );
+
+                    //Assemble the example output
+                    let result_markup = results.to_markup(
+                        statements.last(),
+                        &example_ctx.dimension_registry(),
+                        true,
+                        true,
+                    );
+                    let example_output = &plain_text_format(&result_markup, false);
+
+                    //Print the example
+                    if let Some(example_description) = example_description {
+                        println!("{}", replace_equation_delimiters(example_description));
+                    }
+
+                    print!("<pre>");
+                    print!("<div class=\"buttons\">");
+                    print!("<button class=\"fa fa-play play-button\" title=\"{}\" aria-label=\"{}\"  onclick=\" window.open('{}')\"\"></button>",
+                        "Run this code",
+                        "Run this code",
+                        example_url);
+                    print!("</div>");
+                    print!("<code class=\"language-nbt hljs numbat\">");
+                    for l in example_input.lines() {
+                        println!("{}", l);
+                    }
+                    println!();
+                    for l in example_output.lines() {
+                        println!("{}", l);
+                    }
+                    println!("</code></pre>");
+                    println!();
+                } else {
+                    eprintln!(
+                        "Warning: Example \"{example_code}\" of function {fn_name} did not run successfully."
+                    );
+                }
+            }
+            println!("</details>");
+            println!();
+        }
     }
 }
 
-fn main() {
-    let module_path = Path::new(&std::env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("modules");
+// Replace $..$ with \\( .. \\) for mdbook.
+fn replace_equation_delimiters(text_in: String) -> String {
+    let mut text_out = String::new();
+    for (i, part) in text_in.split('$').enumerate() {
+        if i % 2 == 0 {
+            text_out.push_str(part);
+        } else {
+            text_out.push_str("\\\\( ");
+            text_out.push_str(part);
+            text_out.push_str(" \\\\)");
+        }
+    }
+    return text_out;
+}
 
+fn prepare_context() -> Context {
+    let module_path = Path::new(&std::env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("modules");
     let mut importer = FileSystemImporter::default();
     importer.add_path(module_path);
-    let mut ctx = Context::new(importer);
+    return Context::new(importer);
+}
+
+fn main() {
+    let mut ctx = prepare_context();
     let _result = ctx.interpret("use all", CodeSource::Internal).unwrap();
 
+    let mut example_ctx = prepare_context();
+    let _result = example_ctx
+        .interpret("use prelude", CodeSource::Internal)
+        .unwrap();
+
     let mut args = std::env::args();
     args.next();
     if let Some(arg) = args.next() {
@@ -104,7 +196,7 @@ fn main() {
             "units" => inspect_units(&ctx),
             "functions" => {
                 let module = args.next().unwrap();
-                inspect_functions_in_module(&ctx, module)
+                inspect_functions_in_module(&ctx, &example_ctx, module)
             }
             _ => eprintln!("USAGE: inspect [units|functions <module>]"),
         }

+ 3 - 1
numbat/modules/chemistry/elements.nbt

@@ -49,6 +49,8 @@ fn _convert_from_raw(raw: _ChemicalElementRaw) -> ChemicalElement =
     }
 
 @name("Chemical element")
-@description("Get properties of a chemical element by its symbol or name (case-insensitive). For example: `element(\"H\")` or `element(\"hydrogen\")`.")
+@description("Get properties of a chemical element by its symbol or name (case-insensitive).")
+@example("element(\"H\")", "Get the entire element struct for hydrogen.")
+@example("element(\"hydrogen\").ionization_energy", "Get the ionization energy of hydrogen.")
 fn element(pattern: String) -> ChemicalElement =
     _convert_from_raw(_get_chemical_element_data_raw(pattern))

+ 25 - 4
numbat/modules/core/functions.nbt

@@ -2,64 +2,85 @@ use core::scalar
 
 @name("Identity function")
 @description("Return the input value.")
+@example("id(8 kg)")
 fn id<A>(x: A) -> A = x
 
 @name("Absolute value")
 @description("Return the absolute value $|x|$ of the input. This works for quantities, too: `abs(-5 m) = 5 m`.")
 @url("https://doc.rust-lang.org/std/primitive.f64.html#method.abs")
+@example("abs(-22.2 m)")
 fn abs<T: Dim>(x: T) -> T
 
 @name("Square root")
 @description("Return the square root $\\sqrt\{x\}$ of the input: `sqrt(121 m^2) = 11 m`.")
 @url("https://en.wikipedia.org/wiki/Square_root")
+@example("sqrt(4 are) -> m")
 fn sqrt<D: Dim>(x: D^2) -> D = x^(1/2)
 
 @name("Cube root")
 @description("Return the cube root $\\sqrt[3]\{x\}$ of the input: `cbrt(8 m^3) = 2 m`.")
 @url("https://en.wikipedia.org/wiki/Cube_root")
+@example("cbrt(8 L) -> cm")
 fn cbrt<D: Dim>(x: D^3) -> D = x^(1/3)
 
 @name("Square function")
 @description("Return the square of the input, $x^2$: `sqr(5 m) = 25 m^2`.")
+@example("sqr(7)")
 fn sqr<D: Dim>(x: D) -> D^2 = x^2
 
 @name("Rounding")
 @description("Round to the nearest integer. If the value is half-way between two integers, round away from $0$. See also: `round_in`.")
 @url("https://doc.rust-lang.org/std/primitive.f64.html#method.round")
+@example("round(5.5)")
+@example("round(-5.5)")
 fn round(x: Scalar) -> Scalar
 
 @name("Rounding")
-@description("Round to the nearest multiple of `base`. For example: `round_in(m, 5.3 m) == 5 m`.")
+@description("Round to the nearest multiple of `base`.")
+@example("round_in(m, 5.3 m)", "Round in meters.")
+@example("round_in(cm, 5.3 m)", "Round in centimeters.")
 fn round_in<D: Dim>(base: D, value: D) -> D = round(value / base) × base
 
 @name("Floor function")
 @description("Returns the largest integer less than or equal to $x$. See also: `floor_in`.")
 @url("https://doc.rust-lang.org/std/primitive.f64.html#method.floor")
+@example("floor(5.5)")
 fn floor(x: Scalar) -> Scalar
 
 @name("Floor function")
-@description("Returns the largest integer multiple of `base` less than or equal to `value`. For example: `floor_in(m, 5.7 m) == 5 m`.")
+@description("Returns the largest integer multiple of `base` less than or equal to `value`.")
+@example("floor_in(m, 5.7 m)", "Floor in meters.")
+@example("floor_in(cm, 5.7 m)", "Floor in centimeters.")
 fn floor_in<D: Dim>(base: D, value: D) -> D = floor(value / base) × base
 
 @name("Ceil function")
 @description("Returns the smallest integer greater than or equal to $x$. See also: `ceil_in`.")
 @url("https://doc.rust-lang.org/std/primitive.f64.html#method.ceil")
+@example("ceil(5.5)")
 fn ceil(x: Scalar) -> Scalar
 
 @name("Ceil function")
-@description("Returns the smallest integer multuple of `base` greater than or equal to `value`. For example: `ceil_in(m, 5.3 m) == 6 m`.")
+@description("Returns the smallest integer multiple of `base` greater than or equal to `value`.")
+@example("ceil_in(m, 5.3 m)", "Ceil in meters.")
+@example("ceil_in(cm, 5.3 m)", "Ceil in centimeters.")
+
 fn ceil_in<D: Dim>(base: D, value: D) -> D = ceil(value / base) × base
 
 @name("Truncation")
 @description("Returns the integer part of $x$. Non-integer numbers are always truncated towards zero. See also: `trunc_in`.")
 @url("https://doc.rust-lang.org/std/primitive.f64.html#method.trunc")
+@example("trunc(5.5)")
+@example("trunc(-5.5)")
 fn trunc(x: Scalar) -> Scalar
 
 @name("Truncation")
-@description("Truncates to an integer multiple of `base` (towards zero). For example: `trunc_in(m, -5.7 m) == -5 m`.")
+@description("Truncates to an integer multiple of `base` (towards zero).")
+@example("trunc_in(m, 5.7 m)", "Truncate in meters.")
+@example("trunc_in(cm, 5.7 m)", "Truncate in centimeters.")
 fn trunc_in<D: Dim>(base: D, value: D) -> D = trunc(value / base) × base
 
 @name("Modulo")
 @description("Calculates the least nonnegative remainder of $a (\\mod b)$.")
 @url("https://doc.rust-lang.org/std/primitive.f64.html#method.rem_euclid")
+@example("mod(27, 5)")
 fn mod<T: Dim>(a: T, b: T) -> T

+ 23 - 0
numbat/modules/core/lists.nbt

@@ -3,48 +3,60 @@ use core::error
 use core::strings
 
 @description("Get the length of a list")
+@example("len([3, 2, 1])")
 fn len<A>(xs: List<A>) -> Scalar
 
 @description("Get the first element of a list. Yields a runtime error if the list is empty.")
+@example("head([3, 2, 1])")
 fn head<A>(xs: List<A>) -> A
 
 @description("Get everything but the first element of a list. Yields a runtime error if the list is empty.")
+@example("tail([3, 2, 1])")
 fn tail<A>(xs: List<A>) -> List<A>
 
 @description("Prepend an element to a list")
+@example("cons(77, [3, 2, 1])")
 fn cons<A>(x: A, xs: List<A>) -> List<A>
 
 @description("Append an element to the end of a list")
+@example("cons_end(77, [3, 2, 1])")
 fn cons_end<A>(x: A, xs: List<A>) -> List<A>
 
 @description("Check if a list is empty")
+@example("is_empty([3, 2, 1])")
+@example("is_empty([])")
 fn is_empty<A>(xs: List<A>) -> Bool = xs == []
 
 @description("Concatenate two lists")
+@example("concat([3, 2, 1], [10, 11])")
 fn concat<A>(xs1: List<A>, xs2: List<A>) -> List<A> =
   if is_empty(xs1)
     then xs2
     else cons(head(xs1), concat(tail(xs1), xs2))
 
 @description("Get the first `n` elements of a list")
+@example("take(2, [3, 2, 1, 0])")
 fn take<A>(n: Scalar, xs: List<A>) -> List<A> =
   if n == 0 || is_empty(xs)
     then []
     else cons(head(xs), take(n - 1, tail(xs)))
 
 @description("Get everything but the first `n` elements of a list")
+@example("drop(2, [3, 2, 1, 0])")
 fn drop<A>(n: Scalar, xs: List<A>) -> List<A> =
   if n == 0 || is_empty(xs)
     then xs
     else drop(n - 1, tail(xs))
 
 @description("Get the element at index `i` in a list")
+@example("element_at(2, [3, 2, 1, 0])")
 fn element_at<A>(i: Scalar, xs: List<A>) -> A =
   if i == 0
     then head(xs)
     else element_at(i - 1, tail(xs))
 
 @description("Generate a range of integer numbers from `start` to `end` (inclusive)")
+@example("range(2, 12)")
 fn range(start: Scalar, end: Scalar) -> List<Scalar> =
   if start > end
     then []
@@ -52,18 +64,21 @@ fn range(start: Scalar, end: Scalar) -> List<Scalar> =
 
 
 @description("Reverse the order of a list")
+@example("reverse([3, 2, 1])")
 fn reverse<A>(xs: List<A>) -> List<A> =
   if is_empty(xs)
     then []
     else cons_end(head(xs), reverse(tail(xs)))
 
 @description("Generate a new list by applying a function to each element of the input list")
+@example("map(sqr, [3, 2, 1])", "Square all elements of a list.")
 fn map<A, B>(f: Fn[(A) -> B], xs: List<A>) -> List<B> =
   if is_empty(xs)
     then []
     else cons(f(head(xs)), map(f, tail(xs)))
 
 @description("Filter a list by a predicate")
+@example("filter(is_finite, [0, 1e10, NaN, -inf])")
 fn filter<A>(p: Fn[(A) -> Bool], xs: List<A>) -> List<A> =
   if is_empty(xs)
     then []
@@ -72,6 +87,7 @@ fn filter<A>(p: Fn[(A) -> Bool], xs: List<A>) -> List<A> =
       else filter(p, tail(xs))
 
 @description("Fold a function over a list")
+@example("foldl(str_append, \"\", [\"Num\", \"bat\", \"!\"])", "Join a list of strings by folding.")
 fn foldl<A, B>(f: Fn[(A, B) -> A], acc: A, xs: List<B>) -> A =
   if is_empty(xs)
     then acc
@@ -88,6 +104,7 @@ fn _merge(xs, ys, cmp) =
 
 
 @description("Sort a list of elements, using the given key function that maps the element to a quantity")
+@example("fn last_digit(x) = mod(x, 10)\nsort_by_key(last_digit, [701, 313, 9999, 4])","Sort by last digit.")
 fn sort_by_key<A, D: Dim>(key: Fn[(A) -> D], xs: List<A>) -> List<A> =
   if is_empty(xs)
     then []
@@ -98,9 +115,11 @@ fn sort_by_key<A, D: Dim>(key: Fn[(A) -> D], xs: List<A>) -> List<A> =
                   key)
 
 @description("Sort a list of quantities")
+@example("sort([3, 2, 7, 8, -4, 0, -5])")
 fn sort<D: Dim>(xs: List<D>) -> List<D> = sort_by_key(id, xs)
 
 @description("Add an element between each pair of elements in a list")
+@example("intersperse(0, [1, 1, 1, 1])")
 fn intersperse<A>(sep: A, xs: List<A>) -> List<A> =
   if is_empty(xs)
     then []
@@ -110,6 +129,7 @@ fn intersperse<A>(sep: A, xs: List<A>) -> List<A> =
 
 fn _add(x, y) = x + y # TODO: replace this with a local function once we support them
 @description("Sum all elements of a list")
+@example("sum([3 m, 200 cm, 1000 mm])")
 fn sum<D: Dim>(xs: List<D>) -> D = foldl(_add, 0, xs)
 
 # TODO: implement linspace using `map` or similar once we have closures. This is ugly.
@@ -119,12 +139,14 @@ fn _linspace_helper(start, end, n_steps, i) =
     else cons(start + (end - start) * i / (n_steps - 1), _linspace_helper(start, end, n_steps, i + 1))
 
 @description("Generate a list of `n_steps` evenly spaced numbers from `start` to `end` (inclusive)")
+@example("linspace(-5 m, 5 m, 11)")
 fn linspace<D: Dim>(start: D, end: D, n_steps: Scalar) -> List<D> =
   if n_steps <= 1
     then error("Number of steps must be larger than 1")
     else _linspace_helper(start, end, n_steps, 0)
 
 @description("Convert a list of strings into a single string by concatenating them with a separator")
+@example("join([\"snake\", \"case\"], \"_\")")
 fn join(xs: List<String>, sep: String) =
   if is_empty(xs)
     then ""
@@ -133,6 +155,7 @@ fn join(xs: List<String>, sep: String) =
       else "{head(xs)}{sep}{join(tail(xs), sep)}"
 
 @description("Split a string into a list of strings using a separator")
+@example("split(\"Numbat is a statically typed programming language.\", \" \")")
 fn split(input: String, separator: String) -> List<String> =
   if input == ""
     then []

+ 6 - 0
numbat/modules/core/numbers.nbt

@@ -1,10 +1,16 @@
 @description("Returns true if the input is `NaN`.")
 @url("https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan")
+@example("is_nan(37)")
+@example("is_nan(NaN)")
 fn is_nan<T: Dim>(n: T) -> Bool
 
 @description("Returns true if the input is positive infinity or negative infinity.")
 @url("https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite")
+@example("is_infinite(37)")
+@example("is_infinite(-inf)")
 fn is_infinite<T: Dim>(n: T) -> Bool
 
 @description("Returns true if the input is neither infinite nor `NaN`.")
+@example("is_finite(37)")
+@example("is_finite(-inf)")
 fn is_finite<T: Dim>(n: T) -> Bool = !is_nan(n) && !is_infinite(n)

+ 2 - 0
numbat/modules/core/quantities.nbt

@@ -1,7 +1,9 @@
 use core::scalar
 
 @description("Extract the unit of a quantity (the `km/h` in `20 km/h`). This can be useful in generic code, but should generally be avoided otherwise.")
+@example("unit_of(20 km/h)")
 fn unit_of<T: Dim>(x: T) -> T
 
 @description("Extract the plain value of a quantity (the `20` in `20 km/h`). This can be useful in generic code, but should generally be avoided otherwise.")
+@example("value_of(20 km/h)")
 fn value_of<T: Dim>(x: T) -> Scalar = x / unit_of(x)

+ 22 - 6
numbat/modules/core/strings.nbt

@@ -3,27 +3,35 @@ use core::functions
 use core::error
 
 @description("The length of a string")
+@example("str_length(\"Numbat\")")
 fn str_length(s: String) -> Scalar
 
 @description("Subslice of a string")
+@example("str_slice(\"Numbat\", 3, 6)")
 fn str_slice(s: String, start: Scalar, end: Scalar) -> String
 
-@description("Get a single-character string from a Unicode code point. Example: `0x2764 -> chr`")
+@description("Get a single-character string from a Unicode code point.")
+@example("0x2764 -> chr")
 fn chr(n: Scalar) -> String
 
-@description("Get the Unicode code point of the first character in a string. Example: `\"❤\" -> ord`")
+@description("Get the Unicode code point of the first character in a string.")
+@example("\"❤\" -> ord")
 fn ord(s: String) -> Scalar
 
 @description("Convert a string to lowercase")
+@example("lowercase(\"Numbat\")")
 fn lowercase(s: String) -> String
 
 @description("Convert a string to uppercase")
+@example("uppercase(\"Numbat\")")
 fn uppercase(s: String) -> String
 
 @description("Concatenate two strings")
+@example("str_append(\"Numbat\", \"!\")")
 fn str_append(a: String, b: String) -> String = "{a}{b}"
 
 @description("Find the first occurrence of a substring in a string")
+@example("str_find(\"Numbat is a statically typed programming language.\", \"typed\")")
 fn str_find(haystack: String, needle: String) -> Scalar =
   if len_haystack == 0
     then -1
@@ -36,10 +44,12 @@ fn str_find(haystack: String, needle: String) -> Scalar =
     and tail_haystack = str_slice(haystack, 1, len_haystack)
 
 @description("Check if a string contains a substring")
+@example("str_contains(\"Numbat is a statically typed programming language.\", \"typed\")")
 fn str_contains(haystack: String, needle: String) -> Bool =
   str_find(haystack, needle) != -1
 
 @description("Replace all occurrences of a substring in a string")
+@example("str_replace(\"Numbat is a statically typed programming language.\", \"statically typed programming language\", \"scientific calculator\")")
 fn str_replace(s: String, pattern: String, replacement: String) -> String =
   if pattern == ""
     then s
@@ -50,6 +60,7 @@ fn str_replace(s: String, pattern: String, replacement: String) -> String =
            else s
 
 @description("Repeat the input string `n` times")
+@example("str_repeat(\"abc\", 4)")
 fn str_repeat(a: String, n: Scalar) -> String =
   if n > 0
     then str_append(a, str_repeat(a, n - 1))
@@ -76,7 +87,8 @@ fn _digit_in_base(base: Scalar, x: Scalar) -> String =
 # TODO: once we have anonymous functions / closures, we can implement base in a way
 # that it returns a partially-applied version of '_number_in_base'. This would allow
 # arbitrary 'x -> base(b)' conversions.
-@description("Convert a number to the given base. Example: `42 |> base(16)`")
+@description("Convert a number to the given base.")
+@example("42 |> base(16)")
 fn base(b: Scalar, x: Scalar) -> String =
   if x < 0
     then "-{base(b, -x)}"
@@ -84,14 +96,18 @@ fn base(b: Scalar, x: Scalar) -> String =
       then _digit_in_base(b, x)
       else str_append(base(b, floor(x / b)), _digit_in_base(b, mod(x, b)))
 
-@description("Get a binary representation of a number. Example: `42 -> bin`")
+@description("Get a binary representation of a number.")
+@example("42 -> bin")
 fn bin(x: Scalar) -> String = if x < 0 then "-{bin(-x)}" else "0b{base(2, x)}"
 
-@description("Get an octal representation of a number. Example: `42 -> oct`")
+@description("Get an octal representation of a number.")
+@example("42 -> oct")
 fn oct(x: Scalar) -> String = if x < 0 then "-{oct(-x)}" else "0o{base(8, x)}"
 
 @description("Get a decimal representation of a number.")
+@example("0b111 -> dec")
 fn dec(x: Scalar) -> String = base(10, x)
 
-@description("Get a hexadecimal representation of a number. Example: `2^31-1 -> hex`")
+@description("Get a hexadecimal representation of a number.")
+@example("2^31-1 -> hex")
 fn hex(x: Scalar) -> String = if x < 0 then "-{hex(-x)}" else "0x{base(16, x)}"

+ 14 - 0
numbat/modules/datetime/functions.nbt

@@ -7,15 +7,22 @@ use units::time
 fn now() -> DateTime
 
 @description("Parses a string (date and time) into a `DateTime` object. See [here](./date-and-time.md#date-time-formats) for an overview of the supported formats.")
+@example("datetime(\"2022-07-20T21:52+0200\")")
+@example("datetime(\"2022-07-20 21:52 Europe/Berlin\")")
+@example("datetime(\"2022/07/20 09:52 PM +0200\")")
 fn datetime(input: String) -> DateTime
 
 @description("Formats a `DateTime` object as a string.")
+@example("format_datetime(\"This is a date in %B in the year %Y.\", datetime(\"2022-07-20 21:52 +0200\"))")
 fn format_datetime(format: String, input: DateTime) -> String
 
 @description("Returns the users local timezone.")
+@example("get_local_timezone()")
 fn get_local_timezone() -> String
 
 @description("Returns a timezone conversion function, typically used with the conversion operator.")
+@example("datetime(\"2022-07-20 21:52 +0200\") -> tz(\"Europe/Amsterdam\")")
+@example("datetime(\"2022-07-20 21:52 +0200\") -> tz(\"Asia/Taipei\")")
 fn tz(tz: String) -> Fn[(DateTime) -> DateTime]
 
 @description("Timezone conversion function targeting the users local timezone (`datetime -> local`).")
@@ -25,9 +32,11 @@ let local: Fn[(DateTime) -> DateTime] = tz(get_local_timezone())
 let UTC: Fn[(DateTime) -> DateTime] = tz("UTC")
 
 @description("Converts a `DateTime` to a UNIX timestamp. Can be used on the right hand side of a conversion operator: `now() -> unixtime`.")
+@example("datetime(\"2022-07-20 21:52 +0200\") -> unixtime")
 fn unixtime(input: DateTime) -> Scalar
 
 @description("Converts a UNIX timestamp to a `DateTime` object.")
+@example("from_unixtime(2^31)")
 fn from_unixtime(input: Scalar) -> DateTime
 
 fn _today_str() = format_datetime("%Y-%m-%d", now())
@@ -36,6 +45,7 @@ fn _today_str() = format_datetime("%Y-%m-%d", now())
 fn today() -> DateTime = datetime("{_today_str()} 00:00:00")
 
 @description("Parses a string (only date) into a `DateTime` object.")
+@example("date(\"2022-07-20\")")
 fn date(input: String) -> DateTime =
   if str_contains(input, " ")
     then datetime(str_replace(input, " ", " 00:00:00 "))
@@ -50,6 +60,7 @@ fn _add_months(dt: DateTime, n_months: Scalar) -> DateTime
 fn _add_years(dt: DateTime, n_years: Scalar) -> DateTime
 
 @description("Adds the given time span to a `DateTime`. This uses leap-year and DST-aware calendar arithmetic with variable-length days, months, and years.")
+@example("calendar_add(datetime(\"2022-07-20 21:52 +0200\"), 2 years)")
 fn calendar_add(dt: DateTime, span: Time) -> DateTime =
    if span_unit == days
      then _add_days(dt, span / days)
@@ -65,14 +76,17 @@ fn calendar_add(dt: DateTime, span: Time) -> DateTime =
     span_unit = unit_of(span)
 
 @description("Subtract the given time span from a `DateTime`. This uses leap-year and DST-aware calendar arithmetic with variable-length days, months, and years.")
+@example("calendar_sub(datetime(\"2022-07-20 21:52 +0200\"), 3 years)")
 fn calendar_sub(dt: DateTime, span: Time) -> DateTime =
   calendar_add(dt, -span)
 
 @description("Get the day of the week from a given `DateTime`.")
+@example("weekday(datetime(\"2022-07-20 21:52 +0200\"))")
 fn weekday(dt: DateTime) -> String = format_datetime("%A", dt)
 
 @name("Julian date")
 @description("Convert a `DateTime` to a Julian date, the number of days since the origin of the Julian date system (noon on November 24, 4714 BC in the proleptic Gregorian calendar).")
 @url("https://en.wikipedia.org/wiki/Julian_day")
+@example("julian_date(datetime(\"2022-07-20 21:52 +0200\"))")
 fn julian_date(dt: DateTime) -> Time =
   (dt - datetime("-4713-11-24 12:00:00 +0000")) -> days

+ 1 - 0
numbat/modules/datetime/human.nbt

@@ -33,6 +33,7 @@ fn _human_readable_duration(time: Time, dt: DateTime, num_days: Scalar) -> Strin
 @name("Human-readable time duration")
 @url("https://numbat.dev/doc/date-and-time.html")
 @description("Converts a time duration to a human-readable string in days, hours, minutes and seconds.")
+@example("century/1e6 -> human", "How long is a microcentury?")
 fn human(time: Time) =
   if _human_num_days(time) > 1000
     then "{_human_num_days(time)} days" 

+ 1 - 0
numbat/modules/extra/algebra.nbt

@@ -7,6 +7,7 @@ fn _qe_solution<A: Dim, B: Dim>(a: A, b: B, c: B² / A, sign: Scalar) -> B / A =
 @name("Solve quadratic equations")
 @url("https://en.wikipedia.org/wiki/Quadratic_equation")
 @description("Returns the solutions of the equation a x² + b x + c = 0")
+@example("quadratic_equation(2, -1, -1)", "Solve the equation $2x² -x -1 = 0$")
 fn quadratic_equation<A: Dim, B: Dim>(a: A, b: B, c: B² / A) -> List<B / A> =
   if a == 0
     then if b == 0

+ 9 - 4
numbat/modules/extra/color.nbt

@@ -9,10 +9,12 @@ struct Color {
 }
 
 @description("Create a `Color` from RGB (red, green, blue) values in the range $[0, 256)$.")
+@example("rgb(125, 128, 218)")
 fn rgb(red: Scalar, green: Scalar, blue: Scalar) -> Color =
   Color { red: red, green: green, blue: blue }
 
-@description("Create a `Color` from a (hexadecimal) value, e.g. `color(0xff7700)`")
+@description("Create a `Color` from a (hexadecimal) value.")
+@example("color(0xff7700)")
 fn color(rgb_hex: Scalar) -> Color =
   rgb(
     floor(rgb_hex / 256^2),
@@ -22,15 +24,18 @@ fn color(rgb_hex: Scalar) -> Color =
 fn _color_to_scalar(color: Color) -> Scalar =
   color.red * 0x010000 + color.green * 0x000100 + color.blue
 
-@description("Convert a color to its RGB representation, e.g. `cyan -> color_rgb`")
+@description("Convert a color to its RGB representation.")
+@example("cyan -> color_rgb")
 fn color_rgb(color: Color) -> String =
   "rgb({color.red}, {color.green}, {color.blue})"
 
-@description("Convert a color to its RGB floating point representation, e.g. `cyan -> color_rgb_float`")
+@description("Convert a color to its RGB floating point representation.")
+@example("cyan -> color_rgb_float")
 fn color_rgb_float(color: Color) -> String =
   "rgb({color.red / 255:.3}, {color.green / 255:.3}, {color.blue / 255:.3})"
 
-@description("Convert a color to its hexadecimal representation, e.g. `rgb(225, 36, 143) -> color_hex`")
+@description("Convert a color to its hexadecimal representation.")
+@example("rgb(225, 36, 143) -> color_hex")
 fn color_hex(color: Color) -> String =
   str_append("#", str_replace(str_replace("{color -> _color_to_scalar -> hex:>8}", "0x", ""), " ", "0"))
 

+ 2 - 0
numbat/modules/math/geometry.nbt

@@ -2,9 +2,11 @@ use core::functions
 use math::constants
 
 @description("The length of the hypotenuse of a right-angled triangle $\\sqrt\{x^2+y^2\}$.")
+@example("hypot2(3 m, 4 m)")
 fn hypot2<T: Dim>(x: T, y: T) -> T = sqrt(x^2 + y^2)
 
 @description("The Euclidean norm of a 3D vector $\\sqrt\{x^2+y^2+z^2\}$.")
+@example("hypot3(8, 9, 12)")
 fn hypot3<T: Dim>(x: T, y: T, z: T) -> T = sqrt(x^2 + y^2 + z^2)
 
 # The following functions use a generic dimension instead of

+ 2 - 0
numbat/modules/math/number_theory.nbt

@@ -4,6 +4,7 @@ use core::functions
 @name("Greatest common divisor")
 @description("The largest positive integer that divides each of the integers $a$ and $b$.")
 @url("https://en.wikipedia.org/wiki/Greatest_common_divisor")
+@example("gcd(60, 42)")
 fn gcd(a: Scalar, b: Scalar) -> Scalar =
   if b == 0
     then abs(a)
@@ -12,4 +13,5 @@ fn gcd(a: Scalar, b: Scalar) -> Scalar =
 @name("Least common multiple")
 @description("The smallest positive integer that is divisible by both $a$ and $b$.")
 @url("https://en.wikipedia.org/wiki/Least_common_multiple")
+@example("lcm(14, 4)")
 fn lcm(a: Scalar, b: Scalar) -> Scalar = abs(a * b) / gcd(a, b)

+ 9 - 3
numbat/modules/math/statistics.nbt

@@ -5,38 +5,44 @@ fn _max<D: Dim>(x: D, y: D) -> D = if x > y then x else y
 fn _min<D: Dim>(x: D, y: D) -> D = if x < y then x else y
 
 @name("Maxmimum")
-@description("Get the largest element of a list: `maximum([30 cm, 2 m]) = 2 m`.")
+@description("Get the largest element of a list.")
+@example("maximum([30 cm, 2 m])")
 fn maximum<D: Dim>(xs: List<D>) -> D =
   if len(xs) == 1
     then head(xs)
     else _max(head(xs), maximum(tail(xs)))
 
 @name("Minimum")
-@description("Get the smallest element of a list: `minimum([30 cm, 2 m]) = 30 cm`.")
+@description("Get the smallest element of a list.")
+@example("minimum([30 cm, 2 m])")
 fn minimum<D: Dim>(xs: List<D>) -> D =
   if len(xs) == 1
     then head(xs)
     else _min(head(xs), minimum(tail(xs)))
 
 @name("Arithmetic mean")
-@description("Calculate the arithmetic mean of a list of quantities: `mean([1 m, 2 m, 300 cm]) = 2 m`.")
+@description("Calculate the arithmetic mean of a list of quantities.")
+@example("mean([1 m, 2 m, 300 cm])")
 @url("https://en.wikipedia.org/wiki/Arithmetic_mean")
 fn mean<D: Dim>(xs: List<D>) -> D = if is_empty(xs) then 0 else sum(xs) / len(xs)
 
 @name("Variance")
 @url("https://en.wikipedia.org/wiki/Variance")
 @description("Calculate the population variance of a list of quantities")
+@example("variance([1 m, 2 m, 300 cm])")
 fn variance<D: Dim>(xs: List<D>) -> D^2 =
   mean(map(sqr, xs)) - sqr(mean(xs))
 
 @name("Standard deviation")
 @url("https://en.wikipedia.org/wiki/Standard_deviation")
 @description("Calculate the population standard deviation of a list of quantities")
+@example("stdev([1 m, 2 m, 300 cm])")
 fn stdev<D: Dim>(xs: List<D>) -> D = sqrt(variance(xs))
 
 @name("Median")
 @url("https://en.wikipedia.org/wiki/Median")
 @description("Calculate the median of a list of quantities")
+@example("median([1 m, 2 m, 400 cm])")
 fn median<D: Dim>(xs: List<D>) -> D =  # TODO: this is extremely inefficient
   if mod(n, 2) == 1
     then element_at((n - 1) / 2, sort(xs))

+ 5 - 0
numbat/modules/math/transcendental.nbt

@@ -3,26 +3,31 @@ use core::scalar
 @name("Exponential function")
 @description("The exponential function, $e^x$.")
 @url("https://en.wikipedia.org/wiki/Exponential_function")
+@example("exp(4)")
 fn exp(x: Scalar) -> Scalar
 
 @name("Natural logarithm")
 @description("The natural logarithm with base $e$.")
 @url("https://en.wikipedia.org/wiki/Natural_logarithm")
+@example("ln(20)")
 fn ln(x: Scalar) -> Scalar
 
 @name("Natural logarithm")
 @description("The natural logarithm with base $e$.")
 @url("https://en.wikipedia.org/wiki/Natural_logarithm")
+@example("log(20)")
 fn log(x: Scalar) -> Scalar = ln(x)
 
 @name("Common logarithm")
 @description("The common logarithm with base $10$.")
 @url("https://en.wikipedia.org/wiki/Common_logarithm")
+@example("log10(100)")
 fn log10(x: Scalar) -> Scalar
 
 @name("Binary logarithm")
 @description("The binary logarithm with base $2$.")
 @url("https://en.wikipedia.org/wiki/Binary_logarithm")
+@example("log2(256)")
 fn log2(x: Scalar) -> Scalar
 
 @name("Gamma function")

+ 2 - 0
numbat/modules/numerics/diff.nbt

@@ -3,6 +3,8 @@ use core::quantities
 @name("Numerical differentiation")
 @url("https://en.wikipedia.org/wiki/Numerical_differentiation")
 @description("Compute the numerical derivative of the function $f$ at point $x$ using the central difference method.")
+@example("fn polynomial(x) = x² - x - 1\ndiff(polynomial, 1)", "Compute the derivative of $f(x) = x² -x -1$ at $x=1$.")
+@example("fn distance(t) = 0.5 g0 t²\nfn velocity(t) = diff(distance, t)\nvelocity(2 s)", "Compute the free fall velocity after $t=2 s$.")
 fn diff<X: Dim, Y: Dim>(f: Fn[(X) -> Y], x: X) -> Y / X =
   (f(x + Δx) - f(x - Δx)) / 2 Δx
   where

+ 1 - 0
numbat/modules/numerics/fixed_point.nbt

@@ -15,5 +15,6 @@ fn _fixed_point<X: Dim>(f: Fn[(X) -> X], x0: X, ε: X, max_iter: Scalar) =
 @name("Fixed-point iteration")
 @url("https://en.wikipedia.org/wiki/Fixed-point_iteration")
 @description("Compute the approximate fixed point of a function $f: X \\rightarrow X$ starting from $x_0$, until $|f(x) - x| < ε$.")
+@example("fn function(x) = x/2 - 1\nfixed_point(function, 0, 0.01)", "Compute the fixed poin of $f(x) = x/2 -1$.")
 fn fixed_point<X: Dim>(f: Fn[(X) -> X], x0: X, ε: X) =
   _fixed_point(f, x0, ε, 100)

+ 2 - 0
numbat/modules/numerics/solve.nbt

@@ -4,6 +4,7 @@ use core::error
 @name("Bisection method")
 @url("https://en.wikipedia.org/wiki/Bisection_method")
 @description("Find the root of the function $f$ in the interval $[x_1, x_2]$ using the bisection method. The function $f$ must be continuous and $f(x_1) \cdot f(x_2) < 0$.")
+@example("fn f(x) = x² +x -2\nroot_bisect(f, 0, 100, 0.01, 0.01)", "Find the root of $f(x) = x² +x -2$ in the interval $[0, 100]$.")
 fn root_bisect<X: Dim, Y: Dim>(f: Fn[(X) -> Y], x1: X, x2: X, x_tol: X, y_tol: Y) -> X =
   if abs(x1 - x2) < x_tol
     then x_mean
@@ -27,5 +28,6 @@ fn _root_newton_helper<X: Dim, Y: Dim>(f: Fn[(X) -> Y], f_prime: Fn[(X) -> Y / X
 @name("Newton's method")
 @url("https://en.wikipedia.org/wiki/Newton%27s_method") 
 @description("Find the root of the function $f(x)$ and its derivative $f'(x)$ using Newton's method.")
+@example("fn f(x) = x² -3x +2\nfn f_prime(x) = 2x -3\nroot_newton(f, f_prime, 0 , 0.01)", "Find a root of $f(x) = x² -3x +2$ using Newton's method.")
 fn root_newton<X: Dim, Y: Dim>(f: Fn[(X) -> Y], f_prime: Fn[(X) -> Y / X], x0: X, y_tol: Y) -> X =
   _root_newton_helper(f, f_prime, x0, y_tol, 10_000)

+ 4 - 0
numbat/modules/physics/temperature_conversion.nbt

@@ -5,10 +5,12 @@ use units::si
 let _offset_celsius = 273.15
 
 @description("Converts from degree Celsius (°C) to Kelvin.")
+@example("from_celsius(300)", "300 °C in Kelvin.")
 @url("https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature")
 fn from_celsius(t_celsius: Scalar) -> Temperature = (t_celsius + _offset_celsius) kelvin
 
 @description("Converts from Kelvin to degree Celcius (°C). This can be used on the right hand side of a conversion operator: `200 K -> celsius`.")
+@example("300K -> celsius", "300 K in degree Celsius.")
 @url("https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature")
 fn celsius(t_kelvin: Temperature) -> Scalar = t_kelvin / kelvin - _offset_celsius
 
@@ -16,9 +18,11 @@ let _offset_fahrenheit = 459.67
 let _scale_fahrenheit = 5 / 9
 
 @description("Converts from degree Fahrenheit (°F) to Kelvin.")
+@example("from_fahrenheit(300)", "300 °F in Kelvin.")
 @url("https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature")
 fn from_fahrenheit(t_fahrenheit: Scalar) -> Temperature = ((t_fahrenheit + _offset_fahrenheit) × _scale_fahrenheit) kelvin
 
 @description("Converts from Kelvin to degree Fahrenheit (°F). This can be used on the right hand side of a conversion operator: `200 K -> fahrenheit`.")
+@example("300K -> fahrenheit", "300 K in degree Fahrenheit.")
 @url("https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature")
 fn fahrenheit(t_kelvin: Temperature) -> Scalar = (t_kelvin / kelvin) / _scale_fahrenheit - _offset_fahrenheit

+ 4 - 0
numbat/modules/units/mixed.nbt

@@ -5,11 +5,13 @@ use units::imperial
 @name("Degrees, minutes, seconds")
 @description("Convert an angle to a mixed degrees, (arc)minutes, and (arc)seconds representation. Also called sexagesimal degree notation.")
 @url("https://en.wikipedia.org/wiki/Sexagesimal_degree")
+@example("46.5858° -> DMS")
 fn DMS(alpha: Angle) -> String =
   _mixed_units(alpha, [deg, arcmin, arcsec], ["° ", "′ ", "″"], true)
 
 @name("Degrees, decimal minutes")
 @description("Convert an angle to a mixed degrees and decimal minutes representation.")
+@example("46.5858° -> DM")
 @url("https://en.wikipedia.org/wiki/Decimal_degrees")
 fn DM(alpha: Angle) -> String =
   _mixed_units(alpha, [deg, arcmin], ["° ", "′"], false)
@@ -17,11 +19,13 @@ fn DM(alpha: Angle) -> String =
 @name("Feet and inches")
 @description("Convert a length to a mixed feet and inches representation.")
 @url("https://en.wikipedia.org/wiki/Foot_(unit)")
+@example("180 cm -> feet_and_inches")
 fn feet_and_inches(length: Length) -> String =
   _mixed_units(length, [foot, inch], [" ft ", " in"], false)
 
 @name("Pounds and ounces")
 @description("Convert a mass to a mixed pounds and ounces representation.")
 @url("https://en.wikipedia.org/wiki/Pound_(mass)")
+@example("1 kg -> pounds_and_ounces")
 fn pounds_and_ounces(mass: Mass) -> String =
   _mixed_units(mass, [pound, ounce], [" lb ", " oz"], false)

+ 21 - 0
numbat/src/decorator.rs

@@ -8,6 +8,7 @@ pub enum Decorator<'a> {
     Url(String),
     Name(String),
     Description(String),
+    Example(String, Option<String>),
 }
 
 /// Get an iterator of data computed from a name and/or its alias's `AcceptsPrefix` and
@@ -117,6 +118,16 @@ pub fn description(decorators: &[Decorator]) -> Option<String> {
     }
 }
 
+pub fn examples(decorators: &[Decorator]) -> Vec<(String, Option<String>)> {
+    let mut examples = Vec::new();
+    for decorator in decorators {
+        if let Decorator::Example(example_code, example_description) = decorator {
+            examples.push((example_code.clone(), example_description.clone()));
+        }
+    }
+    return examples;
+}
+
 pub fn contains_aliases_with_prefixes(decorates: &[Decorator]) -> bool {
     for decorator in decorates {
         if let Decorator::Aliases(aliases) = decorator {
@@ -138,3 +149,13 @@ pub fn contains_aliases(decorators: &[Decorator]) -> bool {
 
     false
 }
+
+pub fn contains_examples(decorators: &[Decorator]) -> bool {
+    for decorator in decorators {
+        if let Decorator::Example(_, _) = decorator {
+            return true;
+        }
+    }
+
+    false
+}

+ 2 - 0
numbat/src/lib.rs

@@ -170,6 +170,7 @@ impl Context {
             String,
             Option<String>,
             Option<String>,
+            Vec<(String, Option<String>)>,
             CodeSource,
         ),
     > + '_ {
@@ -187,6 +188,7 @@ impl Context {
                         .to_string(),
                     meta.description.clone(),
                     meta.url.clone(),
+                    meta.examples.clone(),
                     self.resolver
                         .get_code_source(signature.definition_span.code_source_id),
                 )

+ 4 - 0
numbat/src/markup.rs

@@ -208,3 +208,7 @@ impl Formatter for PlainTextFormatter {
         text.to_string()
     }
 }
+
+pub fn plain_text_format(m: &Markup, indent: bool) -> String {
+    PlainTextFormatter {}.format(m, indent)
+}

+ 85 - 0
numbat/src/parser.rs

@@ -198,6 +198,9 @@ pub enum ParseErrorKind {
     #[error("Aliases cannot be used on functions.")]
     AliasUsedOnFunction,
 
+    #[error("Example decorators can only be used on functions.")]
+    ExampleUsedOnUnsuitableKind,
+
     #[error("Numerical overflow in dimension exponent")]
     OverflowInDimensionExponent,
 
@@ -458,6 +461,14 @@ impl<'a> Parser<'a> {
                             span: self.peek(tokens).span,
                         });
                     }
+
+                    if decorator::contains_examples(&self.decorator_stack) {
+                        return Err(ParseError {
+                            kind: ParseErrorKind::ExampleUsedOnUnsuitableKind,
+                            span: self.peek(tokens).span,
+                        });
+                    }
+
                     std::mem::swap(&mut decorators, &mut self.decorator_stack);
                 }
 
@@ -737,6 +748,55 @@ impl<'a> Parser<'a> {
                         });
                     }
                 }
+                "example" => {
+                    if self.match_exact(tokens, TokenKind::LeftParen).is_some() {
+                        if let Some(token_code) = self.match_exact(tokens, TokenKind::StringFixed) {
+                            if self.match_exact(tokens, TokenKind::Comma).is_some() {
+                                //Code and description
+                                if let Some(token_description) =
+                                    self.match_exact(tokens, TokenKind::StringFixed)
+                                {
+                                    if self.match_exact(tokens, TokenKind::RightParen).is_none() {
+                                        return Err(ParseError::new(
+                                            ParseErrorKind::MissingClosingParen,
+                                            self.peek(tokens).span,
+                                        ));
+                                    }
+
+                                    Decorator::Example(
+                                        strip_and_escape(&token_code.lexeme),
+                                        Some(strip_and_escape(&token_description.lexeme)),
+                                    )
+                                } else {
+                                    return Err(ParseError {
+                                        kind: ParseErrorKind::ExpectedString,
+                                        span: self.peek(tokens).span,
+                                    });
+                                }
+                            } else {
+                                //Code but no description
+                                if self.match_exact(tokens, TokenKind::RightParen).is_none() {
+                                    return Err(ParseError::new(
+                                        ParseErrorKind::MissingClosingParen,
+                                        self.peek(tokens).span,
+                                    ));
+                                }
+
+                                Decorator::Example(strip_and_escape(&token_code.lexeme), None)
+                            }
+                        } else {
+                            return Err(ParseError {
+                                kind: ParseErrorKind::ExpectedString,
+                                span: self.peek(tokens).span,
+                            });
+                        }
+                    } else {
+                        return Err(ParseError {
+                            kind: ParseErrorKind::ExpectedLeftParenAfterDecorator,
+                            span: self.peek(tokens).span,
+                        });
+                    }
+                }
                 _ => {
                     return Err(ParseError {
                         kind: ParseErrorKind::UnknownDecorator,
@@ -771,6 +831,13 @@ impl<'a> Parser<'a> {
 
             let unit_name = identifier.lexeme;
 
+            if decorator::contains_examples(&self.decorator_stack) {
+                return Err(ParseError {
+                    kind: ParseErrorKind::ExampleUsedOnUnsuitableKind,
+                    span: self.peek(tokens).span,
+                });
+            }
+
             let mut decorators = vec![];
             std::mem::swap(&mut decorators, &mut self.decorator_stack);
 
@@ -2818,6 +2885,24 @@ mod tests {
             },
         );
 
+        parse_as(
+            &["@name(\"Some function\") @example(\"some_function(2)\", \"Use this function:\") @example(\"let some_var = some_function(0)\") fn some_function(x) = 1"],
+            Statement::DefineFunction {
+                function_name_span: Span::dummy(),
+                function_name: "some_function".into(),
+                type_parameters: vec![],
+                parameters: vec![(Span::dummy(), "x".into(), None)],
+                body: Some(scalar!(1.0)),
+                local_variables: vec![],
+                return_type_annotation: None,
+                decorators: vec![
+                    decorator::Decorator::Name("Some function".into()),
+                    decorator::Decorator::Example("some_function(2)".into(), Some("Use this function:".into())),
+                    decorator::Decorator::Example("let some_var = some_function(0)".into(), None),
+                ],
+            },
+        );
+
         parse_as(
             &["fn double_kef(x) = y where y = x * 2"],
             Statement::DefineFunction {

+ 1 - 1
numbat/src/resolver.rs

@@ -49,7 +49,7 @@ pub struct Resolver {
     pub files: SimpleFiles<String, String>,
     text_code_source_count: usize,
     internal_code_source_count: usize,
-    imported_modules: Vec<ModulePath>,
+    pub imported_modules: Vec<ModulePath>,
     codesources: HashMap<usize, CodeSource>,
 }
 

+ 1 - 0
numbat/src/typechecker/environment.rs

@@ -67,6 +67,7 @@ pub struct FunctionMetadata {
     pub name: Option<String>,
     pub url: Option<String>,
     pub description: Option<String>,
+    pub examples: Vec<(String, Option<String>)>,
 }
 
 #[derive(Clone, Debug)]

+ 1 - 0
numbat/src/typechecker/mod.rs

@@ -1477,6 +1477,7 @@ impl TypeChecker {
                         name: crate::decorator::name(decorators).map(ToOwned::to_owned),
                         url: crate::decorator::url(decorators).map(ToOwned::to_owned),
                         description: crate::decorator::description(decorators),
+                        examples: crate::decorator::examples(decorators),
                     },
                 );
 

+ 11 - 0
numbat/src/typed_ast.rs

@@ -877,6 +877,17 @@ fn decorator_markup(decorators: &Vec<Decorator>) -> Markup {
                         + m::string(description.clone())
                         + m::operator(")")
                 }
+                Decorator::Example(example_code, example_description) => {
+                    m::decorator("@example")
+                        + m::operator("(")
+                        + m::string(example_code.clone())
+                        + if let Some(example_description) = example_description {
+                            m::operator(", ") + m::string(example_description.clone())
+                        } else {
+                            m::empty()
+                        }
+                        + m::operator(")")
+                }
             }
             + m::nl();
     }