Skip to content

Commit

Permalink
Merge pull request #623 from Goju-Ryu/unit_list-utillity-functions
Browse files Browse the repository at this point in the history
Add (unit) list utillity functions
  • Loading branch information
sharkdp authored Oct 24, 2024
2 parents ccf3aca + a5950ff commit da18b78
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 7 deletions.
41 changes: 40 additions & 1 deletion book/src/list-functions-lists.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ sort_by_key(last_digit, [701, 313, 9999, 4])
</details>

### `sort`
Sort a list of quantities.
Sort a list of quantities in ascending order.

```nbt
fn sort<D: Dim>(xs: List<D>) -> List<D>
Expand All @@ -300,6 +300,45 @@ fn sort<D: Dim>(xs: List<D>) -> List<D>

</details>

### `contains`
Returns true if the element `x` is in the list `xs`.

```nbt
fn contains<A>(x: 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=%5B3%2C%202%2C%207%2C%208%2C%20%2D4%2C%200%2C%20%2D5%5D%20%7C%3E%20contains%280%29')""></button></div><code class="language-nbt hljs numbat">>>> [3, 2, 7, 8, -4, 0, -5] |> contains(0)

= 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=%5B3%2C%202%2C%207%2C%208%2C%20%2D4%2C%200%2C%20%2D5%5D%20%7C%3E%20contains%281%29')""></button></div><code class="language-nbt hljs numbat">>>> [3, 2, 7, 8, -4, 0, -5] |> contains(1)

= false [Bool]
</code></pre>

</details>

### `unique`
Remove duplicates from a given list.

```nbt
fn unique<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=unique%28%5B1%2C%202%2C%202%2C%203%2C%203%2C%203%5D%29')""></button></div><code class="language-nbt hljs numbat">>>> unique([1, 2, 2, 3, 3, 3])

= [1, 2, 3] [List<Scalar>]
</code></pre>

</details>

### `intersperse`
Add an element between each pair of elements in a list.

Expand Down
44 changes: 44 additions & 0 deletions book/src/list-functions-other.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,50 @@ fn is_finite<T: Dim>(n: T) -> Bool

</details>

### `is_zero`
Returns true if the input is 0 (zero).

```nbt
fn is_zero<D: Dim>(value: D) -> 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%5Fzero%2837%29')""></button></div><code class="language-nbt hljs numbat">>>> is_zero(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%5Fzero%280%29')""></button></div><code class="language-nbt hljs numbat">>>> is_zero(0)

= true [Bool]
</code></pre>

</details>

### `is_nonzero`
Returns true unless the input is 0 (zero).

```nbt
fn is_nonzero<D: Dim>(value: D) -> 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%5Fnonzero%2837%29')""></button></div><code class="language-nbt hljs numbat">>>> is_nonzero(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%5Fnonzero%280%29')""></button></div><code class="language-nbt hljs numbat">>>> is_nonzero(0)

= false [Bool]
</code></pre>

</details>

## Quantities

Defined in: `core::quantities`
Expand Down
23 changes: 23 additions & 0 deletions examples/tests/lists.nbt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,29 @@ fn negate(x) = -x
assert_eq(sort_by_key(negate, [1, 2, 3]), [3, 2, 1])
assert_eq(sort_by_key(str_length, ["aa", "", "aaaa", "aaa"]), ["", "aa", "aaa", "aaaa"])

# contains:
assert(contains(1, [1]))

assert(contains(1, [1, 2, 3]))
assert(contains(1, [3, 2, 1]))
assert(contains(1, [3, 1, 2]))

assert(!contains(10, [1, 2, 3]))

assert(contains("1", ["1", "2", "3"]))

# unique:
assert_eq(unique([]), [])

assert_eq(unique([1, 2, 3]), [1, 2, 3])

assert_eq(unique([1, 2, 2, 3, 3, 3]), [1, 2, 3])
assert_eq(unique([3, 3, 3, 2, 2, 1]), [3, 2, 1])
assert_eq(unique([1, 3, 2, 3, 2, 3]), [1, 3, 2])

assert_eq(unique([1, 3, 2, 3, 2, 3]), unique(unique([1, 3, 2, 3, 2, 3,])))

# intersperse:
assert_eq(intersperse(0, []), [])
assert_eq(intersperse(0, [1]), [1])
assert_eq(intersperse(0, [1, 2, 3]), [1, 0, 2, 0, 3])
Expand Down
2 changes: 0 additions & 2 deletions examples/tests/mixed_units.nbt
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,3 @@ let test2 = 12 degree + 34 arcminute + 5 arcsec
assert_eq(test2 |> unit_list([degree]) |> head, test2)
assert_eq(test2 |> unit_list([degree, arcmin]) |> sum, test2)
assert_eq(test2 |> unit_list([degree, arcmin, arcsec]) |> sum, test2)


25 changes: 24 additions & 1 deletion numbat/modules/core/lists.nbt
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,33 @@ fn sort_by_key<A, D: Dim>(key: Fn[(A) -> D], xs: List<A>) -> List<A> =
sort_by_key(key, drop(floor(len(xs) / 2), xs)),
key)

@description("Sort a list of quantities")
@description("Sort a list of quantities in ascending order")
@example("sort([3, 2, 7, 8, -4, 0, -5])")
fn sort<D: Dim>(xs: List<D>) -> List<D> = sort_by_key(id, xs)

@description("Returns true if the element `x` is in the list `xs`.")
@example("[3, 2, 7, 8, -4, 0, -5] |> contains(0)")
@example("[3, 2, 7, 8, -4, 0, -5] |> contains(1)")
fn contains<A>(x: A, xs: List<A>) -> Bool =
if is_empty(xs)
then false
else if x == head(xs)
then true
else contains(x, tail(xs))

fn _unique<A>(acc: List<A>, xs: List<A>) -> List<A> =
if is_empty(xs)
then acc
else if is_empty(acc)
then _unique([head(xs)], tail(xs))
else if (acc |> contains(head(xs)))
then _unique(acc, tail(xs))
else _unique((cons_end(head(xs), acc)), tail(xs))

@description("Remove duplicates from a given list.")
@example("unique([1, 2, 2, 3, 3, 3])")
fn unique<A>(xs: List<A>) -> List<A> = xs |> _unique([])

@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> =
Expand Down
10 changes: 10 additions & 0 deletions numbat/modules/core/mixed_units.nbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use core::strings
use core::lists
use core::numbers
use core::quantities

# Helper functions for mixed-unit conversions. See units::mixed for more.

Expand All @@ -15,3 +17,11 @@ fn _mixed_unit_list<D: Dim>(val: D, units: List<D>, acc: List<D>) -> List<D> =
if (len(units) > 0)
then (val |> trunc_in(head(units)))
else error("Units list cannot be empty")

fn _negate<D: Dim>(x: D) = -x

fn _sort_descending<D: Dim>(xs: List<D>) -> List<D> = sort_by_key(_negate, xs)

fn _clean_units<D: Dim>(units: List<D>) -> List<D> = units |> unique() |> _sort_descending()

fn _unit_list<D: Dim>(units: List<D>, value: D) -> List<D> = _mixed_unit_list(value, _clean_units(units), [])
10 changes: 10 additions & 0 deletions numbat/modules/core/numbers.nbt
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ fn is_infinite<T: Dim>(n: T) -> Bool
@example("is_finite(37)")
@example("is_finite(-inf)")
fn is_finite<T: Dim>(n: T) -> Bool = !is_nan(n) && !is_infinite(n)

@description("Returns true if the input is 0 (zero).")
@example("is_zero(37)")
@example("is_zero(0)")
fn is_zero<D: Dim>(value: D) -> Bool = value == 0

@description("Returns true unless the input is 0 (zero).")
@example("is_nonzero(37)")
@example("is_nonzero(0)")
fn is_nonzero<D: Dim>(value: D) -> Bool = !is_zero(value)
1 change: 1 addition & 0 deletions numbat/modules/prelude.nbt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use core::strings
use core::error
use core::random
use core::numbers
use core::mixed_units

use math::constants
use math::transcendental
Expand Down
5 changes: 2 additions & 3 deletions numbat/modules/units/mixed.nbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use units::imperial
@name("Unit list")
@description("Convert a value to a mixed representation using the provided units.")
@example("5500 m |> unit_list([miles, yards, feet, inches])")
fn unit_list<D: Dim>(units: List<D>, value: D) -> List<D> = _mixed_unit_list(value, units, [])
fn unit_list<D: Dim>(units: List<D>, value: D) -> List<D> = _unit_list(units, value)

@name("Degrees, minutes, seconds")
@description("Convert an angle to a mixed degrees, (arc)minutes, and (arc)seconds representation. Also called sexagesimal degree notation.")
Expand Down Expand Up @@ -33,5 +33,4 @@ fn feet_and_inches(length: Length) -> List<Length> =
@url("https://en.wikipedia.org/wiki/Pound_(mass)")
@example("1 kg -> pounds_and_ounces")
fn pounds_and_ounces(mass: Mass) -> List<Mass> =
unit_list([pound, ounce], mass)

unit_list([pound, ounce], mass)

0 comments on commit da18b78

Please sign in to comment.