Merge pull request #28 from gleam-community/refactor/nil-errors

♻️ Replace `String` errors with `Nil`
This commit is contained in:
Nicklas Sindlev Andersen 2024-10-02 20:14:10 +02:00 committed by GitHub
commit 77e13b9254
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 178 additions and 353 deletions

View file

@ -442,7 +442,7 @@ pub fn int_sum(arr: List(Int)) -> Int {
pub fn float_product( pub fn float_product(
arr: List(Float), arr: List(Float),
weights: option.Option(List(Float)), weights: option.Option(List(Float)),
) -> Result(Float, String) { ) -> Result(Float, Nil) {
case arr, weights { case arr, weights {
[], _ -> [], _ ->
1.0 1.0
@ -452,22 +452,16 @@ pub fn float_product(
|> list.fold(1.0, fn(acc, a) { a *. acc }) |> list.fold(1.0, fn(acc, a) { a *. acc })
|> Ok |> Ok
_, option.Some(warr) -> { _, option.Some(warr) -> {
let results = list.zip(arr, warr)
list.zip(arr, warr) |> list.map(fn(a: #(Float, Float)) -> Result(Float, Nil) {
|> list.map(fn(a) { pair.first(a)
pair.first(a) |> elementary.power(pair.second(a))
|> elementary.power(pair.second(a)) })
}) |> result.all
|> result.all |> result.map(fn(prods) {
case results { prods
Ok(prods) -> |> list.fold(1.0, fn(acc: Float, a: Float) -> Float { a *. acc })
prods })
|> list.fold(1.0, fn(acc, a) { a *. acc })
|> Ok
Error(msg) ->
msg
|> Error
}
} }
} }
} }

View file

@ -130,12 +130,10 @@ pub fn combination(
n: Int, n: Int,
k: Int, k: Int,
mode: option.Option(CombinatoricsMode), mode: option.Option(CombinatoricsMode),
) -> Result(Int, String) { ) -> Result(Int, Nil) {
case n, k { case n, k {
_, _ if n < 0 -> _, _ if n < 0 -> Error(Nil)
"Invalid input argument: n < 0. Valid input is n >= 0." |> Error _, _ if k < 0 -> Error(Nil)
_, _ if k < 0 ->
"Invalid input argument: k < 0. Valid input is k >= 0." |> Error
_, _ -> { _, _ -> {
case mode { case mode {
option.Some(WithRepetitions) -> combination_with_repetitions(n, k) option.Some(WithRepetitions) -> combination_with_repetitions(n, k)
@ -145,12 +143,11 @@ pub fn combination(
} }
} }
fn combination_with_repetitions(n: Int, k: Int) -> Result(Int, String) { fn combination_with_repetitions(n: Int, k: Int) -> Result(Int, Nil) {
{ n + k - 1 } combination_without_repetitions(n + k - 1, k)
|> combination_without_repetitions(k)
} }
fn combination_without_repetitions(n: Int, k: Int) -> Result(Int, String) { fn combination_without_repetitions(n: Int, k: Int) -> Result(Int, Nil) {
case n, k { case n, k {
_, _ if k == 0 || k == n -> { _, _ if k == 0 || k == n -> {
1 |> Ok 1 |> Ok
@ -202,17 +199,11 @@ fn combination_without_repetitions(n: Int, k: Int) -> Result(Int, String) {
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn factorial(n) -> Result(Int, String) { pub fn factorial(n) -> Result(Int, Nil) {
case n { case n {
_ if n < 0 -> _ if n < 0 -> Error(Nil)
"Invalid input argument: n < 0. Valid input is n >= 0." 0 -> Ok(1)
|> Error 1 -> Ok(1)
0 ->
1
|> Ok
1 ->
1
|> Ok
_ -> _ ->
list.range(1, n) list.range(1, n)
|> list.fold(1, fn(acc, x) { acc * x }) |> list.fold(1, fn(acc, x) { acc * x })
@ -300,22 +291,16 @@ pub fn permutation(
n: Int, n: Int,
k: Int, k: Int,
mode: option.Option(CombinatoricsMode), mode: option.Option(CombinatoricsMode),
) -> Result(Int, String) { ) -> Result(Int, Nil) {
case n, k { case n, k, mode {
_, _ if n < 0 -> _, _, _ if n < 0 -> Error(Nil)
"Invalid input argument: n < 0. Valid input is n >= 0." |> Error _, _, _ if k < 0 -> Error(Nil)
_, _ if k < 0 -> _, _, option.Some(WithRepetitions) -> permutation_with_repetitions(n, k)
"Invalid input argument: k < 0. Valid input is k >= 0." |> Error _, _, _ -> permutation_without_repetitions(n, k)
_, _ -> {
case mode {
option.Some(WithRepetitions) -> permutation_with_repetitions(n, k)
_ -> permutation_without_repetitions(n, k)
}
}
} }
} }
fn permutation_without_repetitions(n: Int, k: Int) -> Result(Int, String) { fn permutation_without_repetitions(n: Int, k: Int) -> Result(Int, Nil) {
case n, k { case n, k {
_, _ if k < 0 || k > n -> { _, _ if k < 0 || k > n -> {
0 |> Ok 0 |> Ok
@ -330,7 +315,7 @@ fn permutation_without_repetitions(n: Int, k: Int) -> Result(Int, String) {
} }
} }
fn permutation_with_repetitions(n: Int, k: Int) -> Result(Int, String) { fn permutation_with_repetitions(n: Int, k: Int) -> Result(Int, Nil) {
let n_float = conversion.int_to_float(n) let n_float = conversion.int_to_float(n)
let k_float = conversion.int_to_float(k) let k_float = conversion.int_to_float(k)
// 'n' ank 'k' are positive integers, so no errors here... // 'n' ank 'k' are positive integers, so no errors here...
@ -388,29 +373,20 @@ pub fn list_combination(
arr: List(a), arr: List(a),
k: Int, k: Int,
mode: option.Option(CombinatoricsMode), mode: option.Option(CombinatoricsMode),
) -> Result(iterator.Iterator(List(a)), String) { ) -> Result(iterator.Iterator(List(a)), Nil) {
case k { case k, mode {
_ if k < 0 -> _, _ if k < 0 -> Error(Nil)
"Invalid input argument: k < 0. Valid input is k >= 0." _, option.Some(WithRepetitions) -> list_combination_with_repetitions(arr, k)
|> Error _, _ -> list_combination_without_repetitions(arr, k)
_ ->
case mode {
option.Some(WithRepetitions) ->
list_combination_with_repetitions(arr, k)
_ -> list_combination_without_repetitions(arr, k)
}
} }
} }
fn list_combination_without_repetitions( fn list_combination_without_repetitions(
arr: List(a), arr: List(a),
k: Int, k: Int,
) -> Result(iterator.Iterator(List(a)), String) { ) -> Result(iterator.Iterator(List(a)), Nil) {
case k, list.length(arr) { case k, list.length(arr) {
_, arr_length if k > arr_length -> { _, arr_length if k > arr_length -> Error(Nil)
"Invalid input argument: k > length(arr). Valid input is 0 <= k <= length(arr)."
|> Error
}
// Special case: When k = n, then the entire list is the only valid combination // Special case: When k = n, then the entire list is the only valid combination
_, arr_length if k == arr_length -> { _, arr_length if k == arr_length -> {
iterator.single(arr) |> Ok iterator.single(arr) |> Ok
@ -446,7 +422,7 @@ fn do_list_combination_without_repetitions(
fn list_combination_with_repetitions( fn list_combination_with_repetitions(
arr: List(a), arr: List(a),
k: Int, k: Int,
) -> Result(iterator.Iterator(List(a)), String) { ) -> Result(iterator.Iterator(List(a)), Nil) {
Ok(do_list_combination_with_repetitions(iterator.from_list(arr), k, [])) Ok(do_list_combination_with_repetitions(iterator.from_list(arr), k, []))
} }
@ -528,17 +504,12 @@ pub fn list_permutation(
arr: List(a), arr: List(a),
k: Int, k: Int,
mode: option.Option(CombinatoricsMode), mode: option.Option(CombinatoricsMode),
) -> Result(iterator.Iterator(List(a)), String) { ) -> Result(iterator.Iterator(List(a)), Nil) {
case k { case k, mode {
_ if k < 0 -> _, _ if k < 0 -> Error(Nil)
"Invalid input argument: k < 0. Valid input is k >= 0." _, option.Some(WithRepetitions) ->
|> Error Ok(list_permutation_with_repetitions(arr, k))
_ -> _, _ -> list_permutation_without_repetitions(arr, k)
case mode {
option.Some(WithRepetitions) ->
list_permutation_with_repetitions(arr, k)
_ -> list_permutation_without_repetitions(arr, k)
}
} }
} }
@ -558,12 +529,9 @@ fn remove_first_by_index(
fn list_permutation_without_repetitions( fn list_permutation_without_repetitions(
arr: List(a), arr: List(a),
k: Int, k: Int,
) -> Result(iterator.Iterator(List(a)), String) { ) -> Result(iterator.Iterator(List(a)), Nil) {
case k, list.length(arr) { case k, list.length(arr) {
_, arr_length if k > arr_length -> { _, arr_length if k > arr_length -> Error(Nil)
"Invalid input argument: k > length(arr). Valid input is 0 <= k <= length(arr)."
|> Error
}
_, _ -> { _, _ -> {
let indexed_arr = list.index_map(arr, fn(x, i) { #(i, x) }) let indexed_arr = list.index_map(arr, fn(x, i) { #(i, x) })
Ok(do_list_permutation_without_repetitions( Ok(do_list_permutation_without_repetitions(
@ -594,9 +562,9 @@ fn do_list_permutation_without_repetitions(
fn list_permutation_with_repetitions( fn list_permutation_with_repetitions(
arr: List(a), arr: List(a),
k: Int, k: Int,
) -> Result(iterator.Iterator(List(a)), String) { ) -> iterator.Iterator(List(a)) {
let indexed_arr = list.index_map(arr, fn(x, i) { #(i, x) }) let indexed_arr = list.index_map(arr, fn(x, i) { #(i, x) })
Ok(do_list_permutation_with_repetitions(indexed_arr, k)) do_list_permutation_with_repetitions(indexed_arr, k)
} }
fn do_list_permutation_with_repetitions( fn do_list_permutation_with_repetitions(

View file

@ -98,14 +98,10 @@ import gleam/option
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn acos(x: Float) -> Result(Float, String) { pub fn acos(x: Float) -> Result(Float, Nil) {
case x >=. -1.0 && x <=. 1.0 { case x >=. -1.0 && x <=. 1.0 {
True -> True -> Ok(do_acos(x))
do_acos(x) False -> Error(Nil)
|> Ok
False ->
"Invalid input argument: x >= -1 or x <= 1. Valid input is -1. <= x <= 1."
|> Error
} }
} }
@ -150,14 +146,10 @@ fn do_acos(a: Float) -> Float
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn acosh(x: Float) -> Result(Float, String) { pub fn acosh(x: Float) -> Result(Float, Nil) {
case x >=. 1.0 { case x >=. 1.0 {
True -> True -> Ok(do_acosh(x))
do_acosh(x) False -> Error(Nil)
|> Ok
False ->
"Invalid input argument: x < 1. Valid input is x >= 1."
|> Error
} }
} }
@ -205,14 +197,10 @@ fn do_acosh(a: Float) -> Float
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn asin(x: Float) -> Result(Float, String) { pub fn asin(x: Float) -> Result(Float, Nil) {
case x >=. -1.0 && x <=. 1.0 { case x >=. -1.0 && x <=. 1.0 {
True -> True -> Ok(do_asin(x))
do_asin(x) False -> Error(Nil)
|> Ok
False ->
"Invalid input argument: x >= -1 or x <= 1. Valid input is -1. <= x <= 1."
|> Error
} }
} }
@ -394,14 +382,10 @@ fn do_atan2(a: Float, b: Float) -> Float
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn atanh(x: Float) -> Result(Float, String) { pub fn atanh(x: Float) -> Result(Float, Nil) {
case x >. -1.0 && x <. 1.0 { case x >. -1.0 && x <. 1.0 {
True -> True -> Ok(do_atanh(x))
do_atanh(x) False -> Error(Nil)
|> Ok
False ->
"Invalid input argument: x > -1 or x < 1. Valid input is -1. < x < 1."
|> Error
} }
} }
@ -753,14 +737,10 @@ fn do_exponential(a: Float) -> Float
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn natural_logarithm(x: Float) -> Result(Float, String) { pub fn natural_logarithm(x: Float) -> Result(Float, Nil) {
case x >. 0.0 { case x >. 0.0 {
True -> True -> Ok(do_natural_logarithm(x))
do_natural_logarithm(x) False -> Error(Nil)
|> Ok
False ->
"Invalid input argument: x <= 0. Valid input is x > 0."
|> Error
} }
} }
@ -810,30 +790,19 @@ fn do_natural_logarithm(a: Float) -> Float
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn logarithm(x: Float, base: option.Option(Float)) -> Result(Float, String) { pub fn logarithm(x: Float, base: option.Option(Float)) -> Result(Float, Nil) {
case x >. 0.0 { case x >. 0.0, base {
True -> True, option.Some(a) ->
case base { case a >. 0.0 && a != 1.0 {
option.Some(a) -> False -> Error(Nil)
case a >. 0.0 && a != 1.0 { True -> {
True -> { // Apply the "change of base formula"
// Apply the "change of base formula" let assert Ok(numerator) = logarithm_10(x)
let assert Ok(numerator) = logarithm_10(x) let assert Ok(denominator) = logarithm_10(a)
let assert Ok(denominator) = logarithm_10(a) Ok(numerator /. denominator)
numerator /. denominator }
|> Ok
}
False ->
"Invalid input argument: base <= 0 or base == 1. Valid input is base > 0 and base != 1."
|> Error
}
_ ->
"Invalid input argument: base <= 0 or base == 1. Valid input is base > 0 and base != 1."
|> Error
} }
_ -> _, _ -> Error(Nil)
"Invalid input argument: x <= 0. Valid input is x > 0."
|> Error
} }
} }
@ -877,14 +846,10 @@ pub fn logarithm(x: Float, base: option.Option(Float)) -> Result(Float, String)
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn logarithm_2(x: Float) -> Result(Float, String) { pub fn logarithm_2(x: Float) -> Result(Float, Nil) {
case x >. 0.0 { case x >. 0.0 {
True -> True -> Ok(do_logarithm_2(x))
do_logarithm_2(x) False -> Error(Nil)
|> Ok
False ->
"Invalid input argument: x <= 0. Valid input is x > 0."
|> Error
} }
} }
@ -932,14 +897,10 @@ fn do_logarithm_2(a: Float) -> Float
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn logarithm_10(x: Float) -> Result(Float, String) { pub fn logarithm_10(x: Float) -> Result(Float, Nil) {
case x >. 0.0 { case x >. 0.0 {
True -> True -> Ok(do_logarithm_10(x))
do_logarithm_10(x) False -> Error(Nil)
|> Ok
False ->
"Invalid input argument: x <= 0. Valid input is x > 0."
|> Error
} }
} }
@ -993,7 +954,7 @@ fn do_logarithm_10(a: Float) -> Float
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn power(x: Float, y: Float) -> Result(Float, String) { pub fn power(x: Float, y: Float) -> Result(Float, Nil) {
let fractional = 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
@ -1002,9 +963,7 @@ pub fn power(x: Float, y: Float) -> Result(Float, String) {
// expression is equivalent to the exponent (y) divided by 0 and an // expression is equivalent to the exponent (y) divided by 0 and an
// error should be returned // error should be returned
case { x <. 0.0 && fractional } || { x == 0.0 && y <. 0.0 } { case { x <. 0.0 && fractional } || { x == 0.0 && y <. 0.0 } {
True -> True -> Error(Nil)
"Invalid input argument: x < 0 and y is fractional or x = 0 and y < 0."
|> Error
False -> False ->
do_power(x, y) do_power(x, y)
|> Ok |> Ok
@ -1055,19 +1014,13 @@ fn do_ceiling(a: Float) -> Float
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn square_root(x: Float) -> Result(Float, String) { pub fn square_root(x: Float) -> Result(Float, Nil) {
// In the following check: // In the following check:
// 1. If x is negative then return an error as it will otherwise be an // 1. If x is negative then return an error as it will otherwise be an
// imaginary number // imaginary number
case x <. 0.0 { case x <. 0.0 {
True -> True -> Error(Nil)
"Invalid input argument: x < 0." False -> power(x, 1.0 /. 2.0)
|> Error
False -> {
let assert Ok(result) = power(x, 1.0 /. 2.0)
result
|> Ok
}
} }
} }
@ -1107,19 +1060,13 @@ pub fn square_root(x: Float) -> Result(Float, String) {
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn cube_root(x: Float) -> Result(Float, String) { pub fn cube_root(x: Float) -> Result(Float, Nil) {
// In the following check: // In the following check:
// 1. If x is negative then return an error as it will otherwise be an // 1. If x is negative then return an error as it will otherwise be an
// imaginary number // imaginary number
case x <. 0.0 { case x <. 0.0 {
True -> True -> Error(Nil)
"Invalid input argument: x < 0." False -> power(x, 1.0 /. 3.0)
|> Error
False -> {
let assert Ok(result) = power(x, 1.0 /. 3.0)
result
|> Ok
}
} }
} }
@ -1162,25 +1109,13 @@ pub fn cube_root(x: Float) -> Result(Float, String) {
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn nth_root(x: Float, n: Int) -> Result(Float, String) { pub fn nth_root(x: Float, n: Int) -> Result(Float, Nil) {
// In the following check: // In the following check:
// 1. If x is negative then return an error as it will otherwise be an // 1. If x is negative then return an error as it will otherwise be an
// imaginary number // imaginary number
case x <. 0.0 { case x >=. 0.0 && n >= 1 {
True -> True -> power(x, 1.0 /. int.to_float(n))
"Invalid input argument: x < 0. Valid input is x > 0" False -> Error(Nil)
|> Error
False ->
case n >= 1 {
True -> {
let assert Ok(result) = power(x, 1.0 /. int.to_float(n))
result
|> Ok
}
False ->
"Invalid input argument: n < 1. Valid input is n >= 2."
|> Error
}
} }
} }

View file

@ -59,6 +59,7 @@ import gleam/int
import gleam/list import gleam/list
import gleam/option import gleam/option
import gleam/pair import gleam/pair
import gleam/result
import gleam/set import gleam/set
import gleam_community/maths/arithmetics import gleam_community/maths/arithmetics
import gleam_community/maths/conversion import gleam_community/maths/conversion
@ -72,21 +73,15 @@ fn validate_lists(
xarr: List(Float), xarr: List(Float),
yarr: List(Float), yarr: List(Float),
weights: option.Option(List(Float)), weights: option.Option(List(Float)),
) -> Result(Bool, String) { ) -> Result(Bool, Nil) {
case xarr, yarr { case xarr, yarr {
[], _ -> [], _ -> Error(Nil)
"Invalid input argument: The list xarr is empty." _, [] -> Error(Nil)
|> Error
_, [] ->
"Invalid input argument: The list yarr is empty."
|> Error
_, _ -> { _, _ -> {
let xarr_length = list.length(xarr) let xarr_length = list.length(xarr)
let yarr_length = list.length(yarr) let yarr_length = list.length(yarr)
case xarr_length == yarr_length, weights { case xarr_length == yarr_length, weights {
False, _ -> False, _ -> Error(Nil)
"Invalid input argument: length(xarr) != length(yarr). Valid input is when length(xarr) == length(yarr)."
|> Error
True, option.None -> { True, option.None -> {
True True
|> Ok |> Ok
@ -97,9 +92,7 @@ fn validate_lists(
True -> { True -> {
validate_weights(warr) validate_weights(warr)
} }
False -> False -> Error(Nil)
"Invalid input argument: length(weights) != length(xarr) and length(weights) != length(yarr). Valid input is when length(weights) == length(xarr) == length(yarr)."
|> Error
} }
} }
} }
@ -107,16 +100,12 @@ fn validate_lists(
} }
} }
fn validate_weights(warr: List(Float)) -> Result(Bool, String) { fn validate_weights(warr: List(Float)) -> Result(Bool, Nil) {
// Check that all the given weights are positive // Check that all the given weights are positive
let assert Ok(minimum) = piecewise.list_minimum(warr, float.compare) let assert Ok(minimum) = piecewise.list_minimum(warr, float.compare)
case minimum >=. 0.0 { case minimum >=. 0.0 {
False -> False -> Error(Nil)
"Invalid input argument: One or more weights are negative. Valid input is when all weights are >= 0." True -> Ok(True)
|> Error
True ->
True
|> Ok
} }
} }
@ -174,7 +163,7 @@ pub fn norm(
arr: List(Float), arr: List(Float),
p: Float, p: Float,
weights: option.Option(List(Float)), weights: option.Option(List(Float)),
) -> Result(Float, String) { ) -> Result(Float, Nil) {
case arr, weights { case arr, weights {
[], _ -> [], _ ->
0.0 0.0
@ -221,10 +210,7 @@ pub fn norm(
|> Error |> Error
} }
} }
False -> { False -> Error(Nil)
"Invalid input argument: length(weights) != length(arr). Valid input is when length(weights) == length(arr)."
|> Error
}
} }
} }
} }
@ -286,7 +272,7 @@ pub fn manhattan_distance(
xarr: List(Float), xarr: List(Float),
yarr: List(Float), yarr: List(Float),
weights: option.Option(List(Float)), weights: option.Option(List(Float)),
) -> Result(Float, String) { ) -> Result(Float, Nil) {
minkowski_distance(xarr, yarr, 1.0, weights) minkowski_distance(xarr, yarr, 1.0, weights)
} }
@ -354,26 +340,17 @@ pub fn minkowski_distance(
yarr: List(Float), yarr: List(Float),
p: Float, p: Float,
weights: option.Option(List(Float)), weights: option.Option(List(Float)),
) -> Result(Float, String) { ) -> Result(Float, Nil) {
case validate_lists(xarr, yarr, weights) { use _ <- result.try(validate_lists(xarr, yarr, weights))
Error(msg) -> case p <. 1.0 {
msg True -> Error(Nil)
|> Error False -> {
Ok(_) -> { let differences: List(Float) =
case p <. 1.0 { list.zip(xarr, yarr)
True -> |> list.map(fn(tuple: #(Float, Float)) -> Float {
"Invalid input argument: p < 1. Valid input is p >= 1." pair.first(tuple) -. pair.second(tuple)
|> Error })
False -> { norm(differences, p, weights)
let differences =
list.zip(xarr, yarr)
|> list.map(fn(tuple) { pair.first(tuple) -. pair.second(tuple) })
let assert Ok(result) = norm(differences, p, weights)
result
|> Ok
}
}
} }
} }
} }
@ -434,7 +411,7 @@ pub fn euclidean_distance(
xarr: List(Float), xarr: List(Float),
yarr: List(Float), yarr: List(Float),
weights: option.Option(List(Float)), weights: option.Option(List(Float)),
) -> Result(Float, String) { ) -> Result(Float, Nil) {
minkowski_distance(xarr, yarr, 2.0, weights) minkowski_distance(xarr, yarr, 2.0, weights)
} }
@ -484,7 +461,7 @@ pub fn euclidean_distance(
pub fn chebyshev_distance( pub fn chebyshev_distance(
xarr: List(Float), xarr: List(Float),
yarr: List(Float), yarr: List(Float),
) -> Result(Float, String) { ) -> Result(Float, Nil) {
case validate_lists(xarr, yarr, option.None) { case validate_lists(xarr, yarr, option.None) {
Error(msg) -> Error(msg) ->
msg msg
@ -540,11 +517,9 @@ pub fn chebyshev_distance(
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn mean(arr: List(Float)) -> Result(Float, String) { pub fn mean(arr: List(Float)) -> Result(Float, Nil) {
case arr { case arr {
[] -> [] -> Error(Nil)
"Invalid input argument: The list is empty."
|> Error
_ -> _ ->
arr arr
|> arithmetics.float_sum(option.None) |> arithmetics.float_sum(option.None)
@ -664,34 +639,27 @@ fn do_median(
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, String) { pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, Nil) {
case arr { case arr, ddof {
[] -> [], _ -> Error(Nil)
"Invalid input argument: The list is empty." _, _ if ddof < 0 -> Error(Nil)
|> Error _, _ -> {
_ -> let assert Ok(mean) = mean(arr)
case ddof < 0 { arr
True -> |> list.map(fn(a: Float) -> Float {
"Invalid input argument: ddof < 0. Valid input is ddof >= 0." let assert Ok(result) = elementary.power(a -. mean, 2.0)
|> Error result
False -> { })
let assert Ok(mean) = mean(arr) |> arithmetics.float_sum(option.None)
arr |> fn(a: Float) -> Float {
|> list.map(fn(a) { a
let assert Ok(result) = elementary.power(a -. mean, 2.0) /. {
result conversion.int_to_float(list.length(arr))
}) -. conversion.int_to_float(ddof)
|> arithmetics.float_sum(option.None)
|> fn(a) {
a
/. {
conversion.int_to_float(list.length(arr))
-. conversion.int_to_float(ddof)
}
}
|> Ok
} }
} }
|> Ok
}
} }
} }
@ -741,25 +709,18 @@ pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, String) {
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn standard_deviation(arr: List(Float), ddof: Int) -> Result(Float, String) { pub fn standard_deviation(arr: List(Float), ddof: Int) -> Result(Float, Nil) {
case arr { case arr, ddof {
[] -> [], _ -> Error(Nil)
"Invalid input argument: The list is empty." _, _ if ddof < 0 -> Error(Nil)
|> Error _, _ -> {
_ -> let assert Ok(variance) = variance(arr, ddof)
case ddof < 0 { // The computed variance will always be positive
True -> // So an error should never be returned
"Invalid input argument: ddof < 0. Valid input is ddof >= 0." let assert Ok(stdev) = elementary.square_root(variance)
|> Error stdev
False -> { |> Ok
let assert Ok(variance) = variance(arr, ddof) }
// The computed variance will always be positive
// So an error should never be returned
let assert Ok(stdev) = elementary.square_root(variance)
stdev
|> Ok
}
}
} }
} }
@ -924,7 +885,7 @@ pub fn tversky_index(
yset: set.Set(a), yset: set.Set(a),
alpha: Float, alpha: Float,
beta: Float, beta: Float,
) -> Result(Float, String) { ) -> Result(Float, Nil) {
case alpha >=. 0.0, beta >=. 0.0 { case alpha >=. 0.0, beta >=. 0.0 {
True, True -> { True, True -> {
let intersection = let intersection =
@ -943,18 +904,7 @@ pub fn tversky_index(
/. { intersection +. alpha *. difference1 +. beta *. difference2 } /. { intersection +. alpha *. difference1 +. beta *. difference2 }
|> Ok |> Ok
} }
False, True -> { _, _ -> Error(Nil)
"Invalid input argument: alpha < 0. Valid input is alpha >= 0."
|> Error
}
True, False -> {
"Invalid input argument: beta < 0. Valid input is beta >= 0."
|> Error
}
_, _ -> {
"Invalid input argument: alpha < 0 and beta < 0. Valid input is alpha >= 0 and beta >= 0."
|> Error
}
} }
} }
@ -1077,7 +1027,7 @@ pub fn cosine_similarity(
xarr: List(Float), xarr: List(Float),
yarr: List(Float), yarr: List(Float),
weights: option.Option(List(Float)), weights: option.Option(List(Float)),
) -> Result(Float, String) { ) -> Result(Float, Nil) {
case validate_lists(xarr, yarr, weights) { case validate_lists(xarr, yarr, weights) {
Error(msg) -> Error(msg) ->
msg msg
@ -1173,7 +1123,7 @@ pub fn canberra_distance(
xarr: List(Float), xarr: List(Float),
yarr: List(Float), yarr: List(Float),
weights: option.Option(List(Float)), weights: option.Option(List(Float)),
) -> Result(Float, String) { ) -> Result(Float, Nil) {
case validate_lists(xarr, yarr, weights) { case validate_lists(xarr, yarr, weights) {
Error(msg) -> Error(msg) ->
msg msg
@ -1266,7 +1216,7 @@ pub fn braycurtis_distance(
xarr: List(Float), xarr: List(Float),
yarr: List(Float), yarr: List(Float),
weights: option.Option(List(Float)), weights: option.Option(List(Float)),
) -> Result(Float, String) { ) -> Result(Float, Nil) {
case validate_lists(xarr, yarr, weights) { case validate_lists(xarr, yarr, weights) {
Error(msg) -> Error(msg) ->
msg msg

View file

@ -949,11 +949,9 @@ pub fn minmax(x: a, y: a, compare: fn(a, a) -> order.Order) {
pub fn list_minimum( pub fn list_minimum(
arr: List(a), arr: List(a),
compare: fn(a, a) -> order.Order, compare: fn(a, a) -> order.Order,
) -> Result(a, String) { ) -> Result(a, Nil) {
case arr { case arr {
[] -> [] -> Error(Nil)
"Invalid input argument: The list is empty."
|> Error
[x, ..rest] -> [x, ..rest] ->
Ok( Ok(
list.fold(rest, x, fn(acc, element) { list.fold(rest, x, fn(acc, element) {
@ -1003,11 +1001,9 @@ pub fn list_minimum(
pub fn list_maximum( pub fn list_maximum(
arr: List(a), arr: List(a),
compare: fn(a, a) -> order.Order, compare: fn(a, a) -> order.Order,
) -> Result(a, String) { ) -> Result(a, Nil) {
case arr { case arr {
[] -> [] -> Error(Nil)
"Invalid input argument: The list is empty."
|> Error
[x, ..rest] -> [x, ..rest] ->
Ok( Ok(
list.fold(rest, x, fn(acc, element) { list.fold(rest, x, fn(acc, element) {
@ -1063,11 +1059,9 @@ pub fn list_maximum(
pub fn arg_minimum( pub fn arg_minimum(
arr: List(a), arr: List(a),
compare: fn(a, a) -> order.Order, compare: fn(a, a) -> order.Order,
) -> Result(List(Int), String) { ) -> Result(List(Int), Nil) {
case arr { case arr {
[] -> [] -> Error(Nil)
"Invalid input argument: The list is empty."
|> Error
_ -> { _ -> {
let assert Ok(min) = let assert Ok(min) =
arr arr
@ -1133,11 +1127,9 @@ pub fn arg_minimum(
pub fn arg_maximum( pub fn arg_maximum(
arr: List(a), arr: List(a),
compare: fn(a, a) -> order.Order, compare: fn(a, a) -> order.Order,
) -> Result(List(Int), String) { ) -> Result(List(Int), Nil) {
case arr { case arr {
[] -> [] -> Error(Nil)
"Invalid input argument: The list is empty."
|> Error
_ -> { _ -> {
let assert Ok(max) = let assert Ok(max) =
arr arr
@ -1203,11 +1195,9 @@ pub fn arg_maximum(
pub fn extrema( pub fn extrema(
arr: List(a), arr: List(a),
compare: fn(a, a) -> order.Order, compare: fn(a, a) -> order.Order,
) -> Result(#(a, a), String) { ) -> Result(#(a, a), Nil) {
case arr { case arr {
[] -> [] -> Error(Nil)
"Invalid input argument: The list is empty."
|> Error
[x, ..rest] -> [x, ..rest] ->
Ok( Ok(
list.fold(rest, #(x, x), fn(acc, element) { list.fold(rest, #(x, x), fn(acc, element) {

View file

@ -135,7 +135,7 @@ fn float_absolute_difference(a: Float, b: Float) -> Float {
/// let rtol = 0.01 /// let rtol = 0.01
/// let atol = 0.10 /// let atol = 0.10
/// predicates.all_close(xarr, yarr, rtol, atol) /// predicates.all_close(xarr, yarr, rtol, atol)
/// |> fn(zarr), String)) { /// |> fn(zarr: Result(List(Bool), Nil)) -> Result(Bool, Nil) {
/// case zarr { /// case zarr {
/// Ok(arr) -> /// Ok(arr) ->
/// arr /// arr
@ -159,13 +159,11 @@ pub fn all_close(
yarr: List(Float), yarr: List(Float),
rtol: Float, rtol: Float,
atol: Float, atol: Float,
) -> Result(List(Bool), String) { ) -> Result(List(Bool), Nil) {
let xlen = list.length(xarr) let xlen = list.length(xarr)
let ylen = list.length(yarr) let ylen = list.length(yarr)
case xlen == ylen { case xlen == ylen {
False -> False -> Error(Nil)
"Invalid input argument: length(xarr) != length(yarr). Valid input is when length(xarr) == length(yarr)."
|> Error
True -> True ->
list.zip(xarr, yarr) list.zip(xarr, yarr)
|> list.map(fn(z) { is_close(pair.first(z), pair.second(z), rtol, atol) }) |> list.map(fn(z) { is_close(pair.first(z), pair.second(z), rtol, atol) })

View file

@ -160,7 +160,7 @@ pub fn linear_space(
stop: Float, stop: Float,
num: Int, num: Int,
endpoint: Bool, endpoint: Bool,
) -> Result(iterator.Iterator(Float), String) { ) -> Result(iterator.Iterator(Float), Nil) {
let direction = case start <=. stop { let direction = case start <=. stop {
True -> 1.0 True -> 1.0
False -> -1.0 False -> -1.0
@ -184,9 +184,7 @@ pub fn linear_space(
}) })
|> Ok |> Ok
} }
False -> False -> Error(Nil)
"Invalid input: num < 1. Valid input is num >= 1."
|> Error
} }
} }
@ -241,7 +239,7 @@ pub fn logarithmic_space(
num: Int, num: Int,
endpoint: Bool, endpoint: Bool,
base: Float, base: Float,
) -> Result(iterator.Iterator(Float), String) { ) -> Result(iterator.Iterator(Float), Nil) {
case num > 0 { case num > 0 {
True -> { True -> {
let assert Ok(linspace) = linear_space(start, stop, num, endpoint) let assert Ok(linspace) = linear_space(start, stop, num, endpoint)
@ -252,9 +250,7 @@ pub fn logarithmic_space(
}) })
|> Ok |> Ok
} }
False -> False -> Error(Nil)
"Invalid input: num < 1. Valid input is num >= 1."
|> Error
} }
} }
@ -316,11 +312,9 @@ pub fn geometric_space(
stop: Float, stop: Float,
num: Int, num: Int,
endpoint: Bool, endpoint: Bool,
) -> Result(iterator.Iterator(Float), String) { ) -> Result(iterator.Iterator(Float), Nil) {
case start == 0.0 || stop == 0.0 { case start == 0.0 || stop == 0.0 {
True -> True -> Error(Nil)
"Invalid input: Neither 'start' nor 'stop' can be zero, as they must be non-zero for logarithmic calculations."
|> Error
False -> False ->
case num > 0 { case num > 0 {
True -> { True -> {
@ -328,9 +322,7 @@ pub fn geometric_space(
let assert Ok(log_stop) = elementary.logarithm_10(stop) let assert Ok(log_stop) = elementary.logarithm_10(stop)
logarithmic_space(log_start, log_stop, num, endpoint, 10.0) logarithmic_space(log_start, log_stop, num, endpoint, 10.0)
} }
False -> False -> Error(Nil)
"Invalid input: num < 1. Valid input is num >= 1."
|> Error
} }
} }
} }

View file

@ -163,7 +163,7 @@ fn gamma_lanczos(x: Float) -> Float {
/// </a> /// </a>
/// </div> /// </div>
/// ///
pub fn incomplete_gamma(a: Float, x: Float) -> Result(Float, String) { pub fn incomplete_gamma(a: Float, x: Float) -> Result(Float, Nil) {
case a >. 0.0 && x >=. 0.0 { case a >. 0.0 && x >=. 0.0 {
True -> { True -> {
let assert Ok(v) = elementary.power(x, a) let assert Ok(v) = elementary.power(x, a)
@ -173,9 +173,7 @@ pub fn incomplete_gamma(a: Float, x: Float) -> Result(Float, String) {
|> Ok |> Ok
} }
False -> False -> Error(Nil)
"Invalid input argument: a <= 0 or x < 0. Valid input is a > 0 and x >= 0."
|> Error
} }
} }

View file

@ -23,7 +23,7 @@ pub fn float_list_all_close_test() {
let rtol = 0.01 let rtol = 0.01
let atol = 0.1 let atol = 0.1
predicates.all_close(xarr, yarr, rtol, atol) predicates.all_close(xarr, yarr, rtol, atol)
|> fn(zarr) { |> fn(zarr: Result(List(Bool), Nil)) -> Result(Bool, Nil) {
case zarr { case zarr {
Ok(arr) -> Ok(arr) ->
arr arr