Merge branch 'main' into refactor/nil-errors

This commit is contained in:
Nicklas Sindlev Andersen 2024-10-02 20:10:23 +02:00 committed by GitHub
commit eb1b7438e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 172 additions and 188 deletions

View file

@ -86,8 +86,8 @@ import gleam_community/maths/piecewise
/// </div> /// </div>
/// ///
pub fn gcd(x: Int, y: Int) -> Int { pub fn gcd(x: Int, y: Int) -> Int {
let absx: Int = piecewise.int_absolute_value(x) let absx = piecewise.int_absolute_value(x)
let absy: Int = piecewise.int_absolute_value(y) let absy = piecewise.int_absolute_value(y)
do_gcd(absx, absy) do_gcd(absx, absy)
} }
@ -197,8 +197,8 @@ pub fn int_euclidean_modulo(x: Int, y: Int) -> Int {
/// </div> /// </div>
/// ///
pub fn lcm(x: Int, y: Int) -> Int { pub fn lcm(x: Int, y: Int) -> Int {
let absx: Int = piecewise.int_absolute_value(x) let absx = piecewise.int_absolute_value(x)
let absy: Int = piecewise.int_absolute_value(y) let absy = piecewise.int_absolute_value(y)
absx * absy / do_gcd(absx, absy) absx * absy / do_gcd(absx, absy)
} }
@ -240,11 +240,11 @@ pub fn divisors(n: Int) -> List(Int) {
} }
fn find_divisors(n: Int) -> List(Int) { fn find_divisors(n: Int) -> List(Int) {
let nabs: Float = piecewise.float_absolute_value(conversion.int_to_float(n)) let nabs = piecewise.float_absolute_value(conversion.int_to_float(n))
let assert Ok(sqrt_result) = elementary.square_root(nabs) let assert Ok(sqrt_result) = elementary.square_root(nabs)
let max: Int = conversion.float_to_int(sqrt_result) + 1 let max = conversion.float_to_int(sqrt_result) + 1
list.range(2, max) list.range(2, max)
|> list.fold([1, n], fn(acc: List(Int), i: Int) -> List(Int) { |> list.fold([1, n], fn(acc, i) {
case n % i == 0 { case n % i == 0 {
True -> [i, n / i, ..acc] True -> [i, n / i, ..acc]
False -> acc False -> acc
@ -288,7 +288,7 @@ fn find_divisors(n: Int) -> List(Int) {
/// </div> /// </div>
/// ///
pub fn proper_divisors(n: Int) -> List(Int) { pub fn proper_divisors(n: Int) -> List(Int) {
let divisors: List(Int) = find_divisors(n) let divisors = find_divisors(n)
divisors divisors
|> list.take(list.length(divisors) - 1) |> list.take(list.length(divisors) - 1)
} }
@ -340,12 +340,10 @@ pub fn float_sum(arr: List(Float), weights: option.Option(List(Float))) -> Float
[], _ -> 0.0 [], _ -> 0.0
_, option.None -> _, option.None ->
arr arr
|> list.fold(0.0, fn(acc: Float, a: Float) -> Float { a +. acc }) |> list.fold(0.0, fn(acc, a) { a +. acc })
_, option.Some(warr) -> { _, option.Some(warr) -> {
list.zip(arr, warr) list.zip(arr, warr)
|> list.fold(0.0, fn(acc: Float, a: #(Float, Float)) -> Float { |> list.fold(0.0, fn(acc, a) { pair.first(a) *. pair.second(a) +. acc })
pair.first(a) *. pair.second(a) +. acc
})
} }
} }
} }
@ -395,7 +393,7 @@ pub fn int_sum(arr: List(Int)) -> Int {
[] -> 0 [] -> 0
_ -> _ ->
arr arr
|> list.fold(0, fn(acc: Int, a: Int) -> Int { a + acc }) |> list.fold(0, fn(acc, a) { a + acc })
} }
} }
@ -451,7 +449,7 @@ pub fn float_product(
|> Ok |> Ok
_, option.None -> _, option.None ->
arr arr
|> list.fold(1.0, fn(acc: Float, a: Float) -> Float { a *. acc }) |> list.fold(1.0, fn(acc, a) { a *. acc })
|> Ok |> Ok
_, option.Some(warr) -> { _, option.Some(warr) -> {
list.zip(arr, warr) list.zip(arr, warr)
@ -513,7 +511,7 @@ pub fn int_product(arr: List(Int)) -> Int {
[] -> 1 [] -> 1
_ -> _ ->
arr arr
|> list.fold(1, fn(acc: Int, a: Int) -> Int { a * acc }) |> list.fold(1, fn(acc, a) { a * acc })
} }
} }
@ -563,7 +561,7 @@ pub fn float_cumulative_sum(arr: List(Float)) -> List(Float) {
[] -> [] [] -> []
_ -> _ ->
arr arr
|> list.scan(0.0, fn(acc: Float, a: Float) -> Float { a +. acc }) |> list.scan(0.0, fn(acc, a) { a +. acc })
} }
} }
@ -613,7 +611,7 @@ pub fn int_cumulative_sum(arr: List(Int)) -> List(Int) {
[] -> [] [] -> []
_ -> _ ->
arr arr
|> list.scan(0, fn(acc: Int, a: Int) -> Int { a + acc }) |> list.scan(0, fn(acc, a) { a + acc })
} }
} }
@ -665,7 +663,7 @@ pub fn float_cumulative_product(arr: List(Float)) -> List(Float) {
[] -> [] [] -> []
_ -> _ ->
arr arr
|> list.scan(1.0, fn(acc: Float, a: Float) -> Float { a *. acc }) |> list.scan(1.0, fn(acc, a) { a *. acc })
} }
} }
@ -717,6 +715,6 @@ pub fn int_cumulative_product(arr: List(Int)) -> List(Int) {
[] -> [] [] -> []
_ -> _ ->
arr arr
|> list.scan(1, fn(acc: Int, a: Int) -> Int { a * acc }) |> list.scan(1, fn(acc, a) { a * acc })
} }
} }

View file

@ -158,7 +158,7 @@ fn combination_without_repetitions(n: Int, k: Int) -> Result(Int, Nil) {
False -> n - k False -> n - k
} }
list.range(1, min) list.range(1, min)
|> list.fold(1, fn(acc: Int, x: Int) -> Int { acc * { n + 1 - x } / x }) |> list.fold(1, fn(acc, x) { acc * { n + 1 - x } / x })
|> Ok |> Ok
} }
} }
@ -206,7 +206,7 @@ pub fn factorial(n) -> Result(Int, Nil) {
1 -> Ok(1) 1 -> Ok(1)
_ -> _ ->
list.range(1, n) list.range(1, n)
|> list.fold(1, fn(acc: Int, x: Int) -> Int { acc * x }) |> list.fold(1, fn(acc, x) { acc * x })
|> Ok |> Ok
} }
} }
@ -310,7 +310,7 @@ fn permutation_without_repetitions(n: Int, k: Int) -> Result(Int, Nil) {
} }
_, _ -> _, _ ->
list.range(0, k - 1) list.range(0, k - 1)
|> list.fold(1, fn(acc: Int, x: Int) -> Int { acc * { n - x } }) |> list.fold(1, fn(acc, x) { acc * { n - x } })
|> Ok |> Ok
} }
} }
@ -620,18 +620,11 @@ fn do_list_permutation_with_repetitions(
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn cartesian_product(xset: set.Set(a), yset: set.Set(a)) -> set.Set(#(a, a)) { pub fn cartesian_product(xset: set.Set(a), yset: set.Set(b)) -> set.Set(#(a, b)) {
xset xset
|> set.fold( |> set.fold(set.new(), fn(accumulator0: set.Set(#(a, b)), member0: a) {
set.new(), set.fold(yset, accumulator0, fn(accumulator1: set.Set(#(a, b)), member1: b) {
fn(accumulator0: set.Set(#(a, a)), member0: a) -> set.Set(#(a, a)) { set.insert(accumulator1, #(member0, member1))
set.fold( })
yset, })
accumulator0,
fn(accumulator1: set.Set(#(a, a)), member1: a) -> set.Set(#(a, a)) {
set.insert(accumulator1, #(member0, member1))
},
)
},
)
} }

View file

@ -955,7 +955,7 @@ fn do_logarithm_10(a: Float) -> Float
/// </div> /// </div>
/// ///
pub fn power(x: Float, y: Float) -> Result(Float, Nil) { pub fn power(x: Float, y: Float) -> Result(Float, Nil) {
let fractional: Bool = do_ceiling(y) -. y >. 0.0 let fractional = do_ceiling(y) -. y >. 0.0
// In the following check: // In the following check:
// 1. If the base (x) is negative and the exponent (y) is fractional // 1. If the base (x) is negative and the exponent (y) is fractional
// then return an error as it will otherwise be an imaginary number // then return an error as it will otherwise be an imaginary number

View file

@ -78,8 +78,8 @@ fn validate_lists(
[], _ -> Error(Nil) [], _ -> Error(Nil)
_, [] -> Error(Nil) _, [] -> Error(Nil)
_, _ -> { _, _ -> {
let xarr_length: Int = list.length(xarr) let xarr_length = list.length(xarr)
let yarr_length: Int = list.length(yarr) let yarr_length = list.length(yarr)
case xarr_length == yarr_length, weights { case xarr_length == yarr_length, weights {
False, _ -> Error(Nil) False, _ -> Error(Nil)
True, option.None -> { True, option.None -> {
@ -87,7 +87,7 @@ fn validate_lists(
|> Ok |> Ok
} }
True, option.Some(warr) -> { True, option.Some(warr) -> {
let warr_length: Int = list.length(warr) let warr_length = list.length(warr)
case xarr_length == warr_length { case xarr_length == warr_length {
True -> { True -> {
validate_weights(warr) validate_weights(warr)
@ -169,9 +169,9 @@ pub fn norm(
0.0 0.0
|> Ok |> Ok
_, option.None -> { _, option.None -> {
let aggregate: Float = let aggregate =
arr arr
|> list.fold(0.0, fn(accumulator: Float, element: Float) -> Float { |> list.fold(0.0, fn(accumulator, element) {
let assert Ok(result) = let assert Ok(result) =
piecewise.float_absolute_value(element) piecewise.float_absolute_value(element)
|> elementary.power(p) |> elementary.power(p)
@ -182,28 +182,25 @@ pub fn norm(
|> Ok |> Ok
} }
_, option.Some(warr) -> { _, option.Some(warr) -> {
let arr_length: Int = list.length(arr) let arr_length = list.length(arr)
let warr_length: Int = list.length(warr) let warr_length = list.length(warr)
case arr_length == warr_length { case arr_length == warr_length {
True -> { True -> {
case validate_weights(warr) { case validate_weights(warr) {
Ok(_) -> { Ok(_) -> {
let tuples: List(#(Float, Float)) = list.zip(arr, warr) let tuples = list.zip(arr, warr)
let aggregate: Float = let aggregate =
tuples tuples
|> list.fold( |> list.fold(0.0, fn(accumulator, tuple) {
0.0, let first_element = pair.first(tuple)
fn(accumulator: Float, tuple: #(Float, Float)) -> Float { let second_element = pair.second(tuple)
let first_element: Float = pair.first(tuple) let assert Ok(result) =
let second_element: Float = pair.second(tuple) elementary.power(
let assert Ok(result) = piecewise.float_absolute_value(first_element),
elementary.power( p,
piecewise.float_absolute_value(first_element), )
p, second_element *. result +. accumulator
) })
second_element *. result +. accumulator
},
)
let assert Ok(result) = elementary.power(aggregate, 1.0 /. p) let assert Ok(result) = elementary.power(aggregate, 1.0 /. p)
result result
|> Ok |> Ok
@ -353,7 +350,6 @@ pub fn minkowski_distance(
|> list.map(fn(tuple: #(Float, Float)) -> Float { |> list.map(fn(tuple: #(Float, Float)) -> Float {
pair.first(tuple) -. pair.second(tuple) pair.first(tuple) -. pair.second(tuple)
}) })
norm(differences, p, weights) norm(differences, p, weights)
} }
} }
@ -472,7 +468,7 @@ pub fn chebyshev_distance(
|> Error |> Error
Ok(_) -> { Ok(_) -> {
list.zip(xarr, yarr) list.zip(xarr, yarr)
|> list.map(fn(tuple: #(Float, Float)) -> Float { |> list.map(fn(tuple) {
{ pair.first(tuple) -. pair.second(tuple) } { pair.first(tuple) -. pair.second(tuple) }
|> piecewise.float_absolute_value() |> piecewise.float_absolute_value()
}) })
@ -527,9 +523,7 @@ pub fn mean(arr: List(Float)) -> Result(Float, Nil) {
_ -> _ ->
arr arr
|> arithmetics.float_sum(option.None) |> arithmetics.float_sum(option.None)
|> fn(a: Float) -> Float { |> fn(a) { a /. conversion.int_to_float(list.length(arr)) }
a /. conversion.int_to_float(list.length(arr))
}
|> Ok |> Ok
} }
} }
@ -625,7 +619,7 @@ fn do_median(
/// ///
/// pub fn example () { /// pub fn example () {
/// // Degrees of freedom /// // Degrees of freedom
/// let ddof: Int = 1 /// let ddof = 1
/// ///
/// // An empty list returns an error /// // An empty list returns an error
/// [] /// []
@ -695,7 +689,7 @@ pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, Nil) {
/// ///
/// pub fn example () { /// pub fn example () {
/// // Degrees of freedom /// // Degrees of freedom
/// let ddof: Int = 1 /// let ddof = 1
/// ///
/// // An empty list returns an error /// // An empty list returns an error
/// [] /// []
@ -762,8 +756,8 @@ pub fn standard_deviation(arr: List(Float), ddof: Int) -> Result(Float, Nil) {
/// import gleam/set /// import gleam/set
/// ///
/// pub fn example () { /// pub fn example () {
/// let xset: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) /// let xset = set.from_list(["cat", "dog", "hippo", "monkey"])
/// let yset: set.Set(String) = /// let yset =
/// set.from_list(["monkey", "rhino", "ostrich", "salmon"]) /// set.from_list(["monkey", "rhino", "ostrich", "salmon"])
/// metrics.jaccard_index(xset, yset) /// metrics.jaccard_index(xset, yset)
/// |> should.equal(1.0 /. 7.0) /// |> should.equal(1.0 /. 7.0)
@ -814,8 +808,8 @@ pub fn jaccard_index(xset: set.Set(a), yset: set.Set(a)) -> Float {
/// import gleam/set /// import gleam/set
/// ///
/// pub fn example () { /// pub fn example () {
/// let xset: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) /// let xset = set.from_list(["cat", "dog", "hippo", "monkey"])
/// let yset: set.Set(String) = /// let yset =
/// set.from_list(["monkey", "rhino", "ostrich", "salmon", "spider"]) /// set.from_list(["monkey", "rhino", "ostrich", "salmon", "spider"])
/// metrics.sorensen_dice_coefficient(xset, yset) /// metrics.sorensen_dice_coefficient(xset, yset)
/// |> should.equal(2.0 *. 1.0 /. { 4.0 +. 5.0 }) /// |> should.equal(2.0 *. 1.0 /. { 4.0 +. 5.0 })
@ -871,8 +865,8 @@ pub fn sorensen_dice_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float {
/// import gleam/set /// import gleam/set
/// ///
/// pub fn example () { /// pub fn example () {
/// let yset: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) /// let yset = set.from_list(["cat", "dog", "hippo", "monkey"])
/// let xset: set.Set(String) = /// let xset =
/// set.from_list(["monkey", "rhino", "ostrich", "salmon"]) /// set.from_list(["monkey", "rhino", "ostrich", "salmon"])
/// // Test Jaccard index (alpha = beta = 1) /// // Test Jaccard index (alpha = beta = 1)
/// metrics.tversky_index(xset, yset, 1.0, 1.0) /// metrics.tversky_index(xset, yset, 1.0, 1.0)
@ -894,15 +888,15 @@ pub fn tversky_index(
) -> Result(Float, Nil) { ) -> Result(Float, Nil) {
case alpha >=. 0.0, beta >=. 0.0 { case alpha >=. 0.0, beta >=. 0.0 {
True, True -> { True, True -> {
let intersection: Float = let intersection =
set.intersection(xset, yset) set.intersection(xset, yset)
|> set.size() |> set.size()
|> conversion.int_to_float() |> conversion.int_to_float()
let difference1: Float = let difference1 =
set.difference(xset, yset) set.difference(xset, yset)
|> set.size() |> set.size()
|> conversion.int_to_float() |> conversion.int_to_float()
let difference2: Float = let difference2 =
set.difference(yset, xset) set.difference(yset, xset)
|> set.size() |> set.size()
|> conversion.int_to_float() |> conversion.int_to_float()
@ -949,9 +943,9 @@ pub fn tversky_index(
/// import gleam/set /// import gleam/set
/// ///
/// pub fn example () { /// pub fn example () {
/// let set_a: set.Set(String) = /// let set_a =
/// set.from_list(["horse", "dog", "hippo", "monkey", "bird"]) /// set.from_list(["horse", "dog", "hippo", "monkey", "bird"])
/// let set_b: set.Set(String) = /// let set_b =
/// set.from_list(["monkey", "bird", "ostrich", "salmon"]) /// set.from_list(["monkey", "bird", "ostrich", "salmon"])
/// metrics.overlap_coefficient(set_a, set_b) /// metrics.overlap_coefficient(set_a, set_b)
/// |> should.equal(2.0 /. 4.0) /// |> should.equal(2.0 /. 4.0)
@ -965,11 +959,11 @@ pub fn tversky_index(
/// </div> /// </div>
/// ///
pub fn overlap_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float { pub fn overlap_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float {
let intersection: Float = let intersection =
set.intersection(xset, yset) set.intersection(xset, yset)
|> set.size() |> set.size()
|> conversion.int_to_float() |> conversion.int_to_float()
let minsize: Float = let minsize =
piecewise.minimum(set.size(xset), set.size(yset), int.compare) piecewise.minimum(set.size(xset), set.size(yset), int.compare)
|> conversion.int_to_float() |> conversion.int_to_float()
intersection /. minsize intersection /. minsize
@ -1039,36 +1033,34 @@ pub fn cosine_similarity(
msg msg
|> Error |> Error
Ok(_) -> { Ok(_) -> {
let zipped_arr: List(#(Float, Float)) = list.zip(xarr, yarr) let zipped_arr = list.zip(xarr, yarr)
let numerator_elements: List(Float) = let numerator_elements =
zipped_arr zipped_arr
|> list.map(fn(tuple: #(Float, Float)) -> Float { |> list.map(fn(tuple) { pair.first(tuple) *. pair.second(tuple) })
pair.first(tuple) *. pair.second(tuple)
})
case weights { case weights {
option.None -> { option.None -> {
let numerator: Float = let numerator =
numerator_elements numerator_elements
|> arithmetics.float_sum(option.None) |> arithmetics.float_sum(option.None)
let assert Ok(xarr_norm) = norm(xarr, 2.0, option.None) let assert Ok(xarr_norm) = norm(xarr, 2.0, option.None)
let assert Ok(yarr_norm) = norm(yarr, 2.0, option.None) let assert Ok(yarr_norm) = norm(yarr, 2.0, option.None)
let denominator: Float = { let denominator = {
xarr_norm *. yarr_norm xarr_norm *. yarr_norm
} }
numerator /. denominator numerator /. denominator
|> Ok |> Ok
} }
_ -> { _ -> {
let numerator: Float = let numerator =
numerator_elements numerator_elements
|> arithmetics.float_sum(weights) |> arithmetics.float_sum(weights)
let assert Ok(xarr_norm) = norm(xarr, 2.0, weights) let assert Ok(xarr_norm) = norm(xarr, 2.0, weights)
let assert Ok(yarr_norm) = norm(yarr, 2.0, weights) let assert Ok(yarr_norm) = norm(yarr, 2.0, weights)
let denominator: Float = { let denominator = {
xarr_norm *. yarr_norm xarr_norm *. yarr_norm
} }
numerator /. denominator numerator /. denominator
@ -1137,7 +1129,7 @@ pub fn canberra_distance(
msg msg
|> Error |> Error
Ok(_) -> { Ok(_) -> {
let arr: List(Float) = let arr =
list.zip(xarr, yarr) list.zip(xarr, yarr)
|> list.map(canberra_distance_helper) |> list.map(canberra_distance_helper)
@ -1158,9 +1150,9 @@ pub fn canberra_distance(
} }
fn canberra_distance_helper(tuple: #(Float, Float)) -> Float { fn canberra_distance_helper(tuple: #(Float, Float)) -> Float {
let numerator: Float = let numerator =
piecewise.float_absolute_value({ pair.first(tuple) -. pair.second(tuple) }) piecewise.float_absolute_value({ pair.first(tuple) -. pair.second(tuple) })
let denominator: Float = { let denominator = {
piecewise.float_absolute_value(pair.first(tuple)) piecewise.float_absolute_value(pair.first(tuple))
+. piecewise.float_absolute_value(pair.second(tuple)) +. piecewise.float_absolute_value(pair.second(tuple))
} }
@ -1230,17 +1222,17 @@ pub fn braycurtis_distance(
msg msg
|> Error |> Error
Ok(_) -> { Ok(_) -> {
let zipped_arr: List(#(Float, Float)) = list.zip(xarr, yarr) let zipped_arr = list.zip(xarr, yarr)
let numerator_elements: List(Float) = let numerator_elements =
zipped_arr zipped_arr
|> list.map(fn(tuple: #(Float, Float)) -> Float { |> list.map(fn(tuple) {
piecewise.float_absolute_value({ piecewise.float_absolute_value({
pair.first(tuple) -. pair.second(tuple) pair.first(tuple) -. pair.second(tuple)
}) })
}) })
let denominator_elements: List(Float) = let denominator_elements =
zipped_arr zipped_arr
|> list.map(fn(tuple: #(Float, Float)) -> Float { |> list.map(fn(tuple) {
piecewise.float_absolute_value({ piecewise.float_absolute_value({
pair.first(tuple) +. pair.second(tuple) pair.first(tuple) +. pair.second(tuple)
}) })

View file

@ -424,9 +424,9 @@ fn do_round(p: Float, x: Float, mode: option.Option(RoundingMode)) -> Float {
} }
fn round_to_nearest(p: Float, x: Float) -> Float { fn round_to_nearest(p: Float, x: Float) -> Float {
let xabs: Float = float_absolute_value(x) *. p let xabs = float_absolute_value(x) *. p
let xabs_truncated: Float = truncate_float(xabs) let xabs_truncated = truncate_float(xabs)
let remainder: Float = xabs -. xabs_truncated let remainder = xabs -. xabs_truncated
case remainder { case remainder {
_ if remainder >. 0.5 -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p _ if remainder >. 0.5 -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p
_ if remainder == 0.5 -> { _ if remainder == 0.5 -> {
@ -441,8 +441,8 @@ fn round_to_nearest(p: Float, x: Float) -> Float {
} }
fn round_ties_away(p: Float, x: Float) -> Float { fn round_ties_away(p: Float, x: Float) -> Float {
let xabs: Float = float_absolute_value(x) *. p let xabs = float_absolute_value(x) *. p
let remainder: Float = xabs -. truncate_float(xabs) let remainder = xabs -. truncate_float(xabs)
case remainder { case remainder {
_ if remainder >=. 0.5 -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p _ if remainder >=. 0.5 -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p
_ -> float_sign(x) *. truncate_float(xabs) /. p _ -> float_sign(x) *. truncate_float(xabs) /. p
@ -450,9 +450,9 @@ fn round_ties_away(p: Float, x: Float) -> Float {
} }
fn round_ties_up(p: Float, x: Float) -> Float { fn round_ties_up(p: Float, x: Float) -> Float {
let xabs: Float = float_absolute_value(x) *. p let xabs = float_absolute_value(x) *. p
let xabs_truncated: Float = truncate_float(xabs) let xabs_truncated = truncate_float(xabs)
let remainder: Float = xabs -. xabs_truncated let remainder = xabs -. xabs_truncated
case remainder { case remainder {
_ if remainder >=. 0.5 && x >=. 0.0 -> _ if remainder >=. 0.5 && x >=. 0.0 ->
float_sign(x) *. truncate_float(xabs +. 1.0) /. p float_sign(x) *. truncate_float(xabs +. 1.0) /. p
@ -823,7 +823,7 @@ pub fn int_flip_sign(x: Int) -> Int {
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn minimum(x: a, y: a, compare: fn(a, a) -> order.Order) -> a { pub fn minimum(x: a, y: a, compare: fn(a, a) -> order.Order) {
case compare(x, y) { case compare(x, y) {
order.Lt -> x order.Lt -> x
order.Eq -> x order.Eq -> x
@ -869,7 +869,7 @@ pub fn minimum(x: a, y: a, compare: fn(a, a) -> order.Order) -> a {
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn maximum(x: a, y: a, compare: fn(a, a) -> order.Order) -> a { pub fn maximum(x: a, y: a, compare: fn(a, a) -> order.Order) {
case compare(x, y) { case compare(x, y) {
order.Lt -> y order.Lt -> y
order.Eq -> y order.Eq -> y
@ -909,7 +909,7 @@ pub fn maximum(x: a, y: a, compare: fn(a, a) -> order.Order) -> a {
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn minmax(x: a, y: a, compare: fn(a, a) -> order.Order) -> #(a, a) { pub fn minmax(x: a, y: a, compare: fn(a, a) -> order.Order) {
#(minimum(x, y, compare), maximum(x, y, compare)) #(minimum(x, y, compare), maximum(x, y, compare))
} }
@ -954,7 +954,7 @@ pub fn list_minimum(
[] -> Error(Nil) [] -> Error(Nil)
[x, ..rest] -> [x, ..rest] ->
Ok( Ok(
list.fold(rest, x, fn(acc: a, element: a) { list.fold(rest, x, fn(acc, element) {
case compare(element, acc) { case compare(element, acc) {
order.Lt -> element order.Lt -> element
_ -> acc _ -> acc
@ -1006,7 +1006,7 @@ pub fn list_maximum(
[] -> Error(Nil) [] -> Error(Nil)
[x, ..rest] -> [x, ..rest] ->
Ok( Ok(
list.fold(rest, x, fn(acc: a, element: a) { list.fold(rest, x, fn(acc, element) {
case compare(acc, element) { case compare(acc, element) {
order.Lt -> element order.Lt -> element
_ -> acc _ -> acc
@ -1067,13 +1067,13 @@ pub fn arg_minimum(
arr arr
|> list_minimum(compare) |> list_minimum(compare)
arr arr
|> list.index_map(fn(element: a, index: Int) -> Int { |> list.index_map(fn(element, index) {
case compare(element, min) { case compare(element, min) {
order.Eq -> index order.Eq -> index
_ -> -1 _ -> -1
} }
}) })
|> list.filter(fn(index: Int) -> Bool { |> list.filter(fn(index) {
case index { case index {
-1 -> False -1 -> False
_ -> True _ -> True
@ -1135,13 +1135,13 @@ pub fn arg_maximum(
arr arr
|> list_maximum(compare) |> list_maximum(compare)
arr arr
|> list.index_map(fn(element: a, index: Int) -> Int { |> list.index_map(fn(element, index) {
case compare(element, max) { case compare(element, max) {
order.Eq -> index order.Eq -> index
_ -> -1 _ -> -1
} }
}) })
|> list.filter(fn(index: Int) -> Bool { |> list.filter(fn(index) {
case index { case index {
-1 -> False -1 -> False
_ -> True _ -> True
@ -1200,9 +1200,9 @@ pub fn extrema(
[] -> Error(Nil) [] -> Error(Nil)
[x, ..rest] -> [x, ..rest] ->
Ok( Ok(
list.fold(rest, #(x, x), fn(acc: #(a, a), element: a) { list.fold(rest, #(x, x), fn(acc, element) {
let first: a = pair.first(acc) let first = pair.first(acc)
let second: a = pair.second(acc) let second = pair.second(acc)
case compare(element, first), compare(second, element) { case compare(element, first), compare(second, element) {
order.Lt, order.Lt -> #(element, element) order.Lt, order.Lt -> #(element, element)
order.Lt, _ -> #(element, second) order.Lt, _ -> #(element, second)

View file

@ -71,12 +71,12 @@ import gleam_community/maths/piecewise
/// import gleam_community/maths/predicates /// import gleam_community/maths/predicates
/// ///
/// pub fn example () { /// pub fn example () {
/// let val: Float = 99. /// let val = 99.
/// let ref_val: Float = 100. /// let ref_val = 100.
/// // We set 'atol' and 'rtol' such that the values are equivalent /// // We set 'atol' and 'rtol' such that the values are equivalent
/// // if 'val' is within 1 percent of 'ref_val' +/- 0.1 /// // if 'val' is within 1 percent of 'ref_val' +/- 0.1
/// let rtol: Float = 0.01 /// let rtol = 0.01
/// let atol: Float = 0.10 /// let atol = 0.10
/// floatx.is_close(val, ref_val, rtol, atol) /// floatx.is_close(val, ref_val, rtol, atol)
/// |> should.be_true() /// |> should.be_true()
/// } /// }
@ -89,8 +89,8 @@ import gleam_community/maths/piecewise
/// </div> /// </div>
/// ///
pub fn is_close(a: Float, b: Float, rtol: Float, atol: Float) -> Bool { pub fn is_close(a: Float, b: Float, rtol: Float, atol: Float) -> Bool {
let x: Float = float_absolute_difference(a, b) let x = float_absolute_difference(a, b)
let y: Float = atol +. rtol *. float_absolute_value(b) let y = atol +. rtol *. float_absolute_value(b)
case x <=. y { case x <=. y {
True -> True True -> True
False -> False False -> False
@ -126,20 +126,20 @@ fn float_absolute_difference(a: Float, b: Float) -> Float {
/// import gleam_community/maths/predicates /// import gleam_community/maths/predicates
/// ///
/// pub fn example () { /// pub fn example () {
/// let val: Float = 99. /// let val = 99.
/// let ref_val: Float = 100. /// let ref_val = 100.
/// let xarr: List(Float) = list.repeat(val, 42) /// let xarr = list.repeat(val, 42)
/// let yarr: List(Float) = list.repeat(ref_val, 42) /// let yarr = list.repeat(ref_val, 42)
/// // We set 'atol' and 'rtol' such that the values are equivalent /// // We set 'atol' and 'rtol' such that the values are equivalent
/// // if 'val' is within 1 percent of 'ref_val' +/- 0.1 /// // if 'val' is within 1 percent of 'ref_val' +/- 0.1
/// let rtol: Float = 0.01 /// let rtol = 0.01
/// let atol: Float = 0.10 /// let atol = 0.10
/// predicates.all_close(xarr, yarr, rtol, atol) /// predicates.all_close(xarr, yarr, rtol, atol)
/// |> fn(zarr: Result(List(Bool), Nil)) -> Result(Bool, Nil) { /// |> fn(zarr: Result(List(Bool), Nil)) -> Result(Bool, Nil) {
/// case zarr { /// case zarr {
/// Ok(arr) -> /// Ok(arr) ->
/// arr /// arr
/// |> list.all(fn(a: Bool) -> Bool { a }) /// |> list.all(fn(a) { a })
/// |> Ok /// |> Ok
/// _ -> Nil |> Error /// _ -> Nil |> Error
/// } /// }
@ -160,15 +160,13 @@ pub fn all_close(
rtol: Float, rtol: Float,
atol: Float, atol: Float,
) -> Result(List(Bool), Nil) { ) -> Result(List(Bool), Nil) {
let xlen: Int = list.length(xarr) let xlen = list.length(xarr)
let ylen: Int = list.length(yarr) let ylen = list.length(yarr)
case xlen == ylen { case xlen == ylen {
False -> Error(Nil) False -> Error(Nil)
True -> True ->
list.zip(xarr, yarr) list.zip(xarr, yarr)
|> list.map(fn(z: #(Float, Float)) -> Bool { |> list.map(fn(z) { is_close(pair.first(z), pair.second(z), rtol, atol) })
is_close(pair.first(z), pair.second(z), rtol, atol)
})
|> Ok |> Ok
} }
} }
@ -302,7 +300,7 @@ fn do_sum(arr: List(Int)) -> Int {
[] -> 0 [] -> 0
_ -> _ ->
arr arr
|> list.fold(0, fn(acc: Int, a: Int) -> Int { a + acc }) |> list.fold(0, fn(acc, a) { a + acc })
} }
} }
@ -444,7 +442,7 @@ fn miller_rabin_test(n: Int, k: Int) -> Bool {
_, 0 -> True _, 0 -> True
_, _ -> { _, _ -> {
// Generate a random int in the range [2, n] // Generate a random int in the range [2, n]
let random_candidate: Int = 2 + int.random(n - 2) let random_candidate = 2 + int.random(n - 2)
case powmod_with_check(random_candidate, n - 1, n) == 1 { case powmod_with_check(random_candidate, n - 1, n) == 1 {
True -> miller_rabin_test(n, k - 1) True -> miller_rabin_test(n, k - 1)
False -> False False -> False
@ -457,7 +455,7 @@ fn powmod_with_check(base: Int, exponent: Int, modulus: Int) -> Int {
case exponent, { exponent % 2 } == 0 { case exponent, { exponent % 2 } == 0 {
0, _ -> 1 0, _ -> 1
_, True -> { _, True -> {
let x: Int = powmod_with_check(base, exponent / 2, modulus) let x = powmod_with_check(base, exponent / 2, modulus)
case { x * x } % modulus, x != 1 && x != { modulus - 1 } { case { x * x } % modulus, x != 1 && x != { modulus - 1 } {
1, True -> 0 1, True -> 0
_, _ -> { x * x } % modulus _, _ -> { x * x } % modulus

View file

@ -102,7 +102,7 @@ pub fn arange(
|> conversion.float_to_int() |> conversion.float_to_int()
iterator.range(0, num - 1) iterator.range(0, num - 1)
|> iterator.map(fn(i: Int) { |> iterator.map(fn(i) {
start +. conversion.int_to_float(i) *. step_abs *. direction start +. conversion.int_to_float(i) *. step_abs *. direction
}) })
} }
@ -161,7 +161,7 @@ pub fn linear_space(
num: Int, num: Int,
endpoint: Bool, endpoint: Bool,
) -> Result(iterator.Iterator(Float), Nil) { ) -> Result(iterator.Iterator(Float), Nil) {
let direction: Float = case start <=. stop { let direction = case start <=. stop {
True -> 1.0 True -> 1.0
False -> -1.0 False -> -1.0
} }
@ -179,7 +179,7 @@ pub fn linear_space(
case num > 0 { case num > 0 {
True -> { True -> {
iterator.range(0, num - 1) iterator.range(0, num - 1)
|> iterator.map(fn(i: Int) -> Float { |> iterator.map(fn(i) {
start +. conversion.int_to_float(i) *. increment *. direction start +. conversion.int_to_float(i) *. increment *. direction
}) })
|> Ok |> Ok
@ -244,7 +244,7 @@ pub fn logarithmic_space(
True -> { True -> {
let assert Ok(linspace) = linear_space(start, stop, num, endpoint) let assert Ok(linspace) = linear_space(start, stop, num, endpoint)
linspace linspace
|> iterator.map(fn(i: Float) -> Float { |> iterator.map(fn(i) {
let assert Ok(result) = elementary.power(base, i) let assert Ok(result) = elementary.power(base, i)
result result
}) })

View file

@ -76,17 +76,17 @@ pub fn beta(x: Float, y: Float) -> Float {
/// </div> /// </div>
/// ///
pub fn erf(x: Float) -> Float { pub fn erf(x: Float) -> Float {
let assert [a1, a2, a3, a4, a5]: List(Float) = [ let assert [a1, a2, a3, a4, a5] = [
0.254829592, -0.284496736, 1.421413741, -1.453152027, 1.061405429, 0.254829592, -0.284496736, 1.421413741, -1.453152027, 1.061405429,
] ]
let p: Float = 0.3275911 let p = 0.3275911
let sign: Float = piecewise.float_sign(x) let sign = piecewise.float_sign(x)
let x: Float = piecewise.float_absolute_value(x) let x = piecewise.float_absolute_value(x)
// Formula 7.1.26 given in Abramowitz and Stegun. // Formula 7.1.26 given in Abramowitz and Stegun.
let t: Float = 1.0 /. { 1.0 +. p *. x } let t = 1.0 /. { 1.0 +. p *. x }
let y: Float = let y =
1.0 1.0
-. { { { { a5 *. t +. a4 } *. t +. a3 } *. t +. a2 } *. t +. a1 } -. { { { { a5 *. t +. a4 } *. t +. a3 } *. t +. a2 } *. t +. a1 }
*. t *. t
@ -131,14 +131,14 @@ fn gamma_lanczos(x: Float) -> Float {
/. { elementary.sin(elementary.pi() *. x) *. gamma_lanczos(1.0 -. x) } /. { elementary.sin(elementary.pi() *. x) *. gamma_lanczos(1.0 -. x) }
False -> { False -> {
let z = x -. 1.0 let z = x -. 1.0
let x: Float = let x =
list.index_fold(lanczos_p, 0.0, fn(acc: Float, v: Float, index: Int) { list.index_fold(lanczos_p, 0.0, fn(acc, v, index) {
case index > 0 { case index > 0 {
True -> acc +. v /. { z +. conversion.int_to_float(index) } True -> acc +. v /. { z +. conversion.int_to_float(index) }
False -> v False -> v
} }
}) })
let t: Float = z +. lanczos_g +. 0.5 let t = z +. lanczos_g +. 0.5
let assert Ok(v1) = elementary.power(2.0 *. elementary.pi(), 0.5) let assert Ok(v1) = elementary.power(2.0 *. elementary.pi(), 0.5)
let assert Ok(v2) = elementary.power(t, z +. 0.5) let assert Ok(v2) = elementary.power(t, z +. 0.5)
v1 *. v2 *. elementary.exponential(-1.0 *. t) *. x v1 *. v2 *. elementary.exponential(-1.0 *. t) *. x
@ -187,8 +187,8 @@ fn incomplete_gamma_sum(
case t { case t {
0.0 -> s 0.0 -> s
_ -> { _ -> {
let ns: Float = s +. t let ns = s +. t
let nt: Float = t *. { x /. { a +. n } } let nt = t *. { x /. { a +. n } }
incomplete_gamma_sum(a, x, nt, ns, n +. 1.0) incomplete_gamma_sum(a, x, nt, ns, n +. 1.0)
} }
} }

View file

@ -72,7 +72,7 @@ pub fn int_combination_test() {
combinatorics.combination(7, 5, option.Some(combinatorics.WithRepetitions)) combinatorics.combination(7, 5, option.Some(combinatorics.WithRepetitions))
|> should.equal(Ok(462)) |> should.equal(Ok(462))
// NOTE: Tests with the 'combination' function that produce values that exceed // NOTE: Tests with the 'combination' function that produce values that exceed
// precision of the JavaScript 'Number' primitive will result in errors // precision of the JavaScript 'Number' primitive will result in errors
} }
@ -697,4 +697,11 @@ pub fn example_test() {
|> should.equal( |> should.equal(
set.from_list([#(1.0, 1.0), #(1.0, 2.0), #(10.0, 1.0), #(10.0, 2.0)]), set.from_list([#(1.0, 1.0), #(1.0, 2.0), #(10.0, 1.0), #(10.0, 2.0)]),
) )
// Cartesian product of two sets with different types
set.from_list(["1", "10"])
|> combinatorics.cartesian_product(set.from_list([1.0, 2.0]))
|> should.equal(
set.from_list([#("1", 1.0), #("1", 2.0), #("10", 1.0), #("10", 2.0)]),
)
} }

View file

@ -317,7 +317,7 @@ pub fn median_test() {
pub fn variance_test() { pub fn variance_test() {
// Degrees of freedom // Degrees of freedom
let ddof: Int = 1 let ddof = 1
// An empty list returns an error // An empty list returns an error
[] []
@ -332,7 +332,7 @@ pub fn variance_test() {
pub fn standard_deviation_test() { pub fn standard_deviation_test() {
// Degrees of freedom // Degrees of freedom
let ddof: Int = 1 let ddof = 1
// An empty list returns an error // An empty list returns an error
[] []
@ -349,19 +349,18 @@ pub fn jaccard_index_test() {
metrics.jaccard_index(set.from_list([]), set.from_list([])) metrics.jaccard_index(set.from_list([]), set.from_list([]))
|> should.equal(0.0) |> should.equal(0.0)
let set_a: set.Set(Int) = set.from_list([0, 1, 2, 5, 6, 8, 9]) let set_a = set.from_list([0, 1, 2, 5, 6, 8, 9])
let set_b: set.Set(Int) = set.from_list([0, 2, 3, 4, 5, 7, 9]) let set_b = set.from_list([0, 2, 3, 4, 5, 7, 9])
metrics.jaccard_index(set_a, set_b) metrics.jaccard_index(set_a, set_b)
|> should.equal(4.0 /. 10.0) |> should.equal(4.0 /. 10.0)
let set_c: set.Set(Int) = set.from_list([0, 1, 2, 3, 4, 5]) let set_c = set.from_list([0, 1, 2, 3, 4, 5])
let set_d: set.Set(Int) = set.from_list([6, 7, 8, 9, 10]) let set_d = set.from_list([6, 7, 8, 9, 10])
metrics.jaccard_index(set_c, set_d) metrics.jaccard_index(set_c, set_d)
|> should.equal(0.0 /. 11.0) |> should.equal(0.0 /. 11.0)
let set_e: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) let set_e = set.from_list(["cat", "dog", "hippo", "monkey"])
let set_f: set.Set(String) = let set_f = set.from_list(["monkey", "rhino", "ostrich", "salmon"])
set.from_list(["monkey", "rhino", "ostrich", "salmon"])
metrics.jaccard_index(set_e, set_f) metrics.jaccard_index(set_e, set_f)
|> should.equal(1.0 /. 7.0) |> should.equal(1.0 /. 7.0)
} }
@ -370,19 +369,18 @@ pub fn sorensen_dice_coefficient_test() {
metrics.sorensen_dice_coefficient(set.from_list([]), set.from_list([])) metrics.sorensen_dice_coefficient(set.from_list([]), set.from_list([]))
|> should.equal(0.0) |> should.equal(0.0)
let set_a: set.Set(Int) = set.from_list([0, 1, 2, 5, 6, 8, 9]) let set_a = set.from_list([0, 1, 2, 5, 6, 8, 9])
let set_b: set.Set(Int) = set.from_list([0, 2, 3, 4, 5, 7, 9]) let set_b = set.from_list([0, 2, 3, 4, 5, 7, 9])
metrics.sorensen_dice_coefficient(set_a, set_b) metrics.sorensen_dice_coefficient(set_a, set_b)
|> should.equal(2.0 *. 4.0 /. { 7.0 +. 7.0 }) |> should.equal(2.0 *. 4.0 /. { 7.0 +. 7.0 })
let set_c: set.Set(Int) = set.from_list([0, 1, 2, 3, 4, 5]) let set_c = set.from_list([0, 1, 2, 3, 4, 5])
let set_d: set.Set(Int) = set.from_list([6, 7, 8, 9, 10]) let set_d = set.from_list([6, 7, 8, 9, 10])
metrics.sorensen_dice_coefficient(set_c, set_d) metrics.sorensen_dice_coefficient(set_c, set_d)
|> should.equal(2.0 *. 0.0 /. { 6.0 +. 5.0 }) |> should.equal(2.0 *. 0.0 /. { 6.0 +. 5.0 })
let set_e: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) let set_e = set.from_list(["cat", "dog", "hippo", "monkey"])
let set_f: set.Set(String) = let set_f = set.from_list(["monkey", "rhino", "ostrich", "salmon", "spider"])
set.from_list(["monkey", "rhino", "ostrich", "salmon", "spider"])
metrics.sorensen_dice_coefficient(set_e, set_f) metrics.sorensen_dice_coefficient(set_e, set_f)
|> should.equal(2.0 *. 1.0 /. { 4.0 +. 5.0 }) |> should.equal(2.0 *. 1.0 /. { 4.0 +. 5.0 })
} }
@ -391,20 +389,18 @@ pub fn overlap_coefficient_test() {
metrics.overlap_coefficient(set.from_list([]), set.from_list([])) metrics.overlap_coefficient(set.from_list([]), set.from_list([]))
|> should.equal(0.0) |> should.equal(0.0)
let set_a: set.Set(Int) = set.from_list([0, 1, 2, 5, 6, 8, 9]) let set_a = set.from_list([0, 1, 2, 5, 6, 8, 9])
let set_b: set.Set(Int) = set.from_list([0, 2, 3, 4, 5, 7, 9]) let set_b = set.from_list([0, 2, 3, 4, 5, 7, 9])
metrics.overlap_coefficient(set_a, set_b) metrics.overlap_coefficient(set_a, set_b)
|> should.equal(4.0 /. 7.0) |> should.equal(4.0 /. 7.0)
let set_c: set.Set(Int) = set.from_list([0, 1, 2, 3, 4, 5]) let set_c = set.from_list([0, 1, 2, 3, 4, 5])
let set_d: set.Set(Int) = set.from_list([6, 7, 8, 9, 10]) let set_d = set.from_list([6, 7, 8, 9, 10])
metrics.overlap_coefficient(set_c, set_d) metrics.overlap_coefficient(set_c, set_d)
|> should.equal(0.0 /. 5.0) |> should.equal(0.0 /. 5.0)
let set_e: set.Set(String) = let set_e = set.from_list(["horse", "dog", "hippo", "monkey", "bird"])
set.from_list(["horse", "dog", "hippo", "monkey", "bird"]) let set_f = set.from_list(["monkey", "bird", "ostrich", "salmon"])
let set_f: set.Set(String) =
set.from_list(["monkey", "bird", "ostrich", "salmon"])
metrics.overlap_coefficient(set_e, set_f) metrics.overlap_coefficient(set_e, set_f)
|> should.equal(2.0 /. 4.0) |> should.equal(2.0 /. 4.0)
} }
@ -440,7 +436,7 @@ pub fn cosine_similarity_test() {
metrics.cosine_similarity([-1.0, -2.0, -3.0], [1.0, 2.0, 3.0], option.None) metrics.cosine_similarity([-1.0, -2.0, -3.0], [1.0, 2.0, 3.0], option.None)
|> should.equal(Ok(-1.0)) |> should.equal(Ok(-1.0))
// Try with arbitrary valid input // Try with arbitrary valid input
let assert Ok(result) = let assert Ok(result) =
metrics.cosine_similarity([1.0, 2.0, 3.0], [4.0, 5.0, 6.0], option.None) metrics.cosine_similarity([1.0, 2.0, 3.0], [4.0, 5.0, 6.0], option.None)
result result

View file

@ -3,31 +3,31 @@ import gleam_community/maths/predicates
import gleeunit/should import gleeunit/should
pub fn float_is_close_test() { pub fn float_is_close_test() {
let val: Float = 99.0 let val = 99.0
let ref_val: Float = 100.0 let ref_val = 100.0
// We set 'atol' and 'rtol' such that the values are equivalent // We set 'atol' and 'rtol' such that the values are equivalent
// if 'val' is within 1 percent of 'ref_val' +/- 0.1 // if 'val' is within 1 percent of 'ref_val' +/- 0.1
let rtol: Float = 0.01 let rtol = 0.01
let atol: Float = 0.1 let atol = 0.1
predicates.is_close(val, ref_val, rtol, atol) predicates.is_close(val, ref_val, rtol, atol)
|> should.be_true() |> should.be_true()
} }
pub fn float_list_all_close_test() { pub fn float_list_all_close_test() {
let val: Float = 99.0 let val = 99.0
let ref_val: Float = 100.0 let ref_val = 100.0
let xarr: List(Float) = list.repeat(val, 42) let xarr = list.repeat(val, 42)
let yarr: List(Float) = list.repeat(ref_val, 42) let yarr = list.repeat(ref_val, 42)
// We set 'atol' and 'rtol' such that the values are equivalent // We set 'atol' and 'rtol' such that the values are equivalent
// if 'val' is within 1 percent of 'ref_val' +/- 0.1 // if 'val' is within 1 percent of 'ref_val' +/- 0.1
let rtol: Float = 0.01 let rtol = 0.01
let atol: Float = 0.1 let atol = 0.1
predicates.all_close(xarr, yarr, rtol, atol) predicates.all_close(xarr, yarr, rtol, atol)
|> fn(zarr: Result(List(Bool), Nil)) -> Result(Bool, Nil) { |> fn(zarr: Result(List(Bool), Nil)) -> Result(Bool, Nil) {
case zarr { case zarr {
Ok(arr) -> Ok(arr) ->
arr arr
|> list.all(fn(a: Bool) -> Bool { a }) |> list.all(fn(a) { a })
|> Ok |> Ok
_ -> _ ->
Nil Nil