diff options
Diffstat (limited to 'aoc2023/build/packages/gleam_stdlib/src/gleam/int.gleam')
-rw-r--r-- | aoc2023/build/packages/gleam_stdlib/src/gleam/int.gleam | 874 |
1 files changed, 874 insertions, 0 deletions
diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/int.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/int.gleam new file mode 100644 index 0000000..d93c16a --- /dev/null +++ b/aoc2023/build/packages/gleam_stdlib/src/gleam/int.gleam @@ -0,0 +1,874 @@ +//// Functions for working with integers. +//// +//// ## Division by zero +//// +//// In Erlang division by zero results in a crash, however Gleam does not have +//// partial functions and operators in core so instead division by zero returns +//// zero, a behaviour taken from Pony, Coq, and Lean. +//// +//// This may seem unexpected at first, but it is no less mathematically valid +//// than crashing or returning a special value. Division by zero is undefined +//// in mathematics. + +import gleam/float +import gleam/order.{type Order} + +/// Returns the absolute value of the input. +/// +/// ## Examples +/// +/// ```gleam +/// > absolute_value(-12) +/// 12 +/// ``` +/// +/// ```gleam +/// > absolute_value(10) +/// 10 +/// ``` +/// +pub fn absolute_value(x: Int) -> Int { + case x >= 0 { + True -> x + False -> x * -1 + } +} + +/// Returns the results of the base being raised to the power of the +/// exponent, as a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// > power(2, -1.0) +/// Ok(0.5) +/// ``` +/// +/// ```gleam +/// > power(2, 2.0) +/// Ok(4.0) +/// ``` +/// +/// ```gleam +/// > power(8, 1.5) +/// Ok(22.627416997969522) +/// ``` +/// +/// ```gleam +/// > 4 |> power(of: 2.0) +/// Ok(16.0) +/// ``` +/// +/// ```gleam +/// > power(-1, 0.5) +/// Error(Nil) +/// ``` +/// +pub fn power(base: Int, of exponent: Float) -> Result(Float, Nil) { + base + |> to_float() + |> float.power(exponent) +} + +/// Returns the square root of the input as a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// > square_root(4) +/// Ok(2.0) +/// ``` +/// +/// ```gleam +/// > square_root(-16) +/// Error(Nil) +/// ``` +/// +pub fn square_root(x: Int) -> Result(Float, Nil) { + x + |> to_float() + |> float.square_root() +} + +/// Parses a given string as an int if possible. +/// +/// ## Examples +/// +/// ```gleam +/// > parse("2") +/// Ok(2) +/// ``` +/// +/// ```gleam +/// > parse("ABC") +/// Error(Nil) +/// ``` +/// +pub fn parse(string: String) -> Result(Int, Nil) { + do_parse(string) +} + +@external(erlang, "gleam_stdlib", "parse_int") +@external(javascript, "../gleam_stdlib.mjs", "parse_int") +fn do_parse(a: String) -> Result(Int, Nil) + +/// Parses a given string as an int in a given base if possible. +/// Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`. +/// +/// ## Examples +/// +/// ```gleam +/// > base_parse("10", 2) +/// Ok(2) +/// +/// > base_parse("30", 16) +/// Ok(48) +/// +/// > base_parse("1C", 36) +/// Ok(48) +/// +/// > base_parse("48", 1) +/// Error(Nil) +/// +/// > base_parse("48", 37) +/// Error(Nil) +/// ``` +/// +pub fn base_parse(string: String, base: Int) -> Result(Int, Nil) { + case base >= 2 && base <= 36 { + True -> do_base_parse(string, base) + False -> Error(Nil) + } +} + +@external(erlang, "gleam_stdlib", "int_from_base_string") +@external(javascript, "../gleam_stdlib.mjs", "int_from_base_string") +fn do_base_parse(a: String, b: Int) -> Result(Int, Nil) + +/// Prints a given int to a string. +/// +/// ## Examples +/// +/// ```gleam +/// > to_string(2) +/// "2" +/// ``` +/// +pub fn to_string(x: Int) { + do_to_string(x) +} + +@external(erlang, "erlang", "integer_to_binary") +@external(javascript, "../gleam_stdlib.mjs", "to_string") +fn do_to_string(a: Int) -> String + +/// Error value when trying to operate with a base out of the allowed range. +/// +pub type InvalidBase { + InvalidBase +} + +/// Prints a given int to a string using the base number provided. +/// Supports only bases 2 to 36, for values outside of which this function returns an `Error(InvalidBase)`. +/// For common bases (2, 8, 16, 36), use the `to_baseN` functions. +/// +/// ## Examples +/// +/// ```gleam +/// > to_base_string(2, 2) +/// Ok("10") +/// ``` +/// +/// ```gleam +/// > to_base_string(48, 16) +/// Ok("30") +/// ``` +/// +/// ```gleam +/// > to_base_string(48, 36) +/// Ok("1C") +/// ``` +/// +/// ```gleam +/// > to_base_string(48, 1) +/// Error(InvalidBase) +/// ``` +/// +/// ```gleam +/// > to_base_string(48, 37) +/// Error(InvalidBase) +/// ``` +/// +pub fn to_base_string(x: Int, base: Int) -> Result(String, InvalidBase) { + case base >= 2 && base <= 36 { + True -> Ok(do_to_base_string(x, base)) + False -> Error(InvalidBase) + } +} + +@external(erlang, "erlang", "integer_to_binary") +@external(javascript, "../gleam_stdlib.mjs", "int_to_base_string") +fn do_to_base_string(a: Int, b: Int) -> String + +/// Prints a given int to a string using base-2. +/// +/// ## Examples +/// +/// ```gleam +/// > to_base2(2) +/// "10" +/// ``` +/// +pub fn to_base2(x: Int) -> String { + do_to_base_string(x, 2) +} + +/// Prints a given int to a string using base-8. +/// +/// ## Examples +/// +/// ```gleam +/// > to_base8(15) +/// "17" +/// ``` +/// +pub fn to_base8(x: Int) -> String { + do_to_base_string(x, 8) +} + +/// Prints a given int to a string using base-16. +/// +/// ## Examples +/// +/// ```gleam +/// > to_base16(48) +/// "30" +/// ``` +/// +pub fn to_base16(x: Int) -> String { + do_to_base_string(x, 16) +} + +/// Prints a given int to a string using base-36. +/// +/// ## Examples +/// +/// ```gleam +/// > to_base36(48) +/// "1C" +/// ``` +/// +pub fn to_base36(x: Int) -> String { + do_to_base_string(x, 36) +} + +/// Takes an int and returns its value as a float. +/// +/// ## Examples +/// +/// ```gleam +/// > to_float(5) +/// 5.0 +/// ``` +/// +/// ```gleam +/// > to_float(0) +/// 0.0 +/// ``` +/// +/// ```gleam +/// > to_float(-3) +/// -3.0 +/// ``` +/// +pub fn to_float(x: Int) -> Float { + do_to_float(x) +} + +@external(erlang, "erlang", "float") +@external(javascript, "../gleam_stdlib.mjs", "identity") +fn do_to_float(a: Int) -> Float + +/// Restricts an int between a lower and upper bound. +/// +/// ## Examples +/// +/// ```gleam +/// > clamp(40, min: 50, max: 60) +/// 50 +/// ``` +/// +pub fn clamp(x: Int, min min_bound: Int, max max_bound: Int) -> Int { + x + |> min(max_bound) + |> max(min_bound) +} + +/// Compares two ints, returning an order. +/// +/// ## Examples +/// +/// ```gleam +/// > compare(2, 3) +/// Lt +/// ``` +/// +/// ```gleam +/// > compare(4, 3) +/// Gt +/// ``` +/// +/// ```gleam +/// > compare(3, 3) +/// Eq +/// ``` +/// +pub fn compare(a: Int, with b: Int) -> Order { + case a == b { + True -> order.Eq + False -> + case a < b { + True -> order.Lt + False -> order.Gt + } + } +} + +/// Compares two ints, returning the smaller of the two. +/// +/// ## Examples +/// +/// ```gleam +/// > min(2, 3) +/// 2 +/// ``` +/// +pub fn min(a: Int, b: Int) -> Int { + case a < b { + True -> a + False -> b + } +} + +/// Compares two ints, returning the larger of the two. +/// +/// ## Examples +/// +/// ```gleam +/// > max(2, 3) +/// 3 +/// ``` +/// +pub fn max(a: Int, b: Int) -> Int { + case a > b { + True -> a + False -> b + } +} + +/// Returns whether the value provided is even. +/// +/// ## Examples +/// +/// ```gleam +/// > is_even(2) +/// True +/// ``` +/// +/// ```gleam +/// > is_even(3) +/// False +/// ``` +/// +pub fn is_even(x: Int) -> Bool { + x % 2 == 0 +} + +/// Returns whether the value provided is odd. +/// +/// ## Examples +/// +/// ```gleam +/// > is_odd(3) +/// True +/// ``` +/// +/// ```gleam +/// > is_odd(2) +/// False +/// ``` +/// +pub fn is_odd(x: Int) -> Bool { + x % 2 != 0 +} + +/// Returns the negative of the value provided. +/// +/// ## Examples +/// +/// ```gleam +/// > negate(1) +/// -1 +/// ``` +/// +pub fn negate(x: Int) -> Int { + -1 * x +} + +/// Sums a list of ints. +/// +/// ## Example +/// +/// ```gleam +/// > sum([1, 2, 3]) +/// 6 +/// ``` +/// +pub fn sum(numbers: List(Int)) -> Int { + numbers + |> do_sum(0) +} + +fn do_sum(numbers: List(Int), initial: Int) -> Int { + case numbers { + [] -> initial + [x, ..rest] -> do_sum(rest, x + initial) + } +} + +/// Multiplies a list of ints and returns the product. +/// +/// ## Example +/// +/// ```gleam +/// > product([2, 3, 4]) +/// 24 +/// ``` +/// +pub fn product(numbers: List(Int)) -> Int { + case numbers { + [] -> 1 + _ -> do_product(numbers, 1) + } +} + +fn do_product(numbers: List(Int), initial: Int) -> Int { + case numbers { + [] -> initial + [x, ..rest] -> do_product(rest, x * initial) + } +} + +/// Splits an integer into its digit representation in the specified base +/// +/// ## Examples +/// +/// ```gleam +/// > digits(234, 10) +/// Ok([2,3,4]) +/// ``` +/// +/// ```gleam +/// > digits(234, 1) +/// Error(InvalidBase) +/// ``` +/// +pub fn digits(x: Int, base: Int) -> Result(List(Int), InvalidBase) { + case base < 2 { + True -> Error(InvalidBase) + False -> Ok(do_digits(x, base, [])) + } +} + +fn do_digits(x: Int, base: Int, acc: List(Int)) -> List(Int) { + case absolute_value(x) < base { + True -> [x, ..acc] + False -> do_digits(x / base, base, [x % base, ..acc]) + } +} + +/// Joins a list of digits into a single value. +/// Returns an error if the base is less than 2 or if the list contains a digit greater than or equal to the specified base. +/// +/// ## Examples +/// +/// ```gleam +/// > undigits([2,3,4], 10) +/// Ok(234) +/// ``` +/// +/// ```gleam +/// > undigits([2,3,4], 1) +/// Error(InvalidBase) +/// ``` +/// +/// ```gleam +/// > undigits([2,3,4], 2) +/// Error(InvalidBase) +/// ``` +/// +pub fn undigits(numbers: List(Int), base: Int) -> Result(Int, InvalidBase) { + case base < 2 { + True -> Error(InvalidBase) + False -> do_undigits(numbers, base, 0) + } +} + +fn do_undigits( + numbers: List(Int), + base: Int, + acc: Int, +) -> Result(Int, InvalidBase) { + case numbers { + [] -> Ok(acc) + [digit, ..] if digit >= base -> Error(InvalidBase) + [digit, ..rest] -> do_undigits(rest, base, acc * base + digit) + } +} + +/// Generates a random int between the given minimum and maximum values. +/// +/// ## Examples +/// +/// ```gleam +/// > random(1, 5) +/// 2 +/// ``` +/// +pub fn random(min: Int, max: Int) -> Int { + float.random(to_float(min), to_float(max)) + |> float.floor() + |> float.round() +} + +/// Performs a truncated integer division. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// > divide(0, 1) +/// Ok(1) +/// ``` +/// +/// ```gleam +/// > divide(1, 0) +/// Error(Nil) +/// ``` +/// +/// ```gleam +/// > divide(5, 2) +/// Ok(2) +/// ``` +/// +/// ```gleam +/// > divide(-99, 2) +/// Ok(-49) +/// ``` +/// +pub fn divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + divisor -> Ok(dividend / divisor) + } +} + +/// Computes the remainder of an integer division of inputs as a `Result`. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// Most the time you will want to use the `%` operator instead of this +/// function. +/// +/// ## Examples +/// +/// ```gleam +/// > remainder(3, 2) +/// Ok(1) +/// ``` +/// +/// ```gleam +/// > remainder(1, 0) +/// Error(Nil) +/// ``` +/// +/// ```gleam +/// > remainder(10, -1) +/// Ok(0) +/// ``` +/// +/// ```gleam +/// > remainder(13, by: 3) +/// Ok(1) +/// ``` +/// +/// ```gleam +/// > remainder(-13, by: 3) +/// Ok(-1) +/// ``` +/// +/// ```gleam +/// > remainder(13, by: -3) +/// Ok(1) +/// ``` +/// +/// ```gleam +/// > remainder(-13, by: -3) +/// Ok(-1) +/// ``` +/// +pub fn remainder(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + divisor -> Ok(dividend % divisor) + } +} + +/// Computes the modulo of an integer division of inputs as a `Result`. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// Most the time you will want to use the `%` operator instead of this +/// function. +/// +/// ## Examples +/// +/// ```gleam +/// > modulo(3, 2) +/// Ok(1) +/// ``` +/// +/// ```gleam +/// > modulo(1, 0) +/// Error(Nil) +/// ``` +/// +/// ```gleam +/// > modulo(10, -1) +/// Ok(0) +/// ``` +/// +/// ```gleam +/// > modulo(13, by: 3) +/// Ok(1) +/// ``` +/// +/// ```gleam +/// > modulo(-13, by: 3) +/// Ok(2) +/// ``` +/// +/// ```gleam +/// > modulo(13, by: -3) +/// Ok(-2) +/// ``` +/// +/// ```gleam +/// > modulo(-13, by: -3) +/// Ok(-1) +/// ``` +/// +pub fn modulo(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + _ -> { + let remainder = dividend % divisor + case remainder * divisor < 0 { + True -> Ok(remainder + divisor) + False -> Ok(remainder) + } + } + } +} + +/// Performs a *floored* integer division, which means that the result will +/// always be rounded towards negative infinity. +/// +/// If you want to perform truncated integer division (rounding towards zero), +/// use `int.divide()` or the `/` operator instead. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// > floor_divide(1, 0) +/// Error(Nil) +/// ``` +/// +/// ```gleam +/// > floor_divide(5, 2) +/// Ok(2) +/// ``` +/// +/// ```gleam +/// > floor_divide(6, -4) +/// Ok(-2) +/// ``` +/// +/// ```gleam +/// > floor_divide(-99, 2) +/// Ok(-50) +/// ``` +/// +pub fn floor_divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + divisor -> + case dividend * divisor < 0 && dividend % divisor != 0 { + True -> Ok(dividend / divisor - 1) + False -> Ok(dividend / divisor) + } + } +} + +/// Adds two integers together. +/// +/// It's the function equivalent of the `+` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// > add(1, 2) +/// 3 +/// ``` +/// +/// ```gleam +/// import gleam/list +/// > list.fold([1, 2, 3], 0, add) +/// 6 +/// ``` +/// +/// ```gleam +/// > 3 |> add(2) +/// 5 +/// ``` +/// +pub fn add(a: Int, b: Int) -> Int { + a + b +} + +/// Multiplies two integers together. +/// +/// It's the function equivalent of the `*` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// > multiply(2, 4) +/// 8 +/// ``` +/// +/// ```gleam +/// import gleam/list +/// > list.fold([2, 3, 4], 1, multiply) +/// 24 +/// ``` +/// +/// ```gleam +/// > 3 |> multiply(2) +/// 6 +/// ``` +/// +pub fn multiply(a: Int, b: Int) -> Int { + a * b +} + +/// Subtracts one int from another. +/// +/// It's the function equivalent of the `-` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// > subtract(3, 1) +/// 2.0 +/// ``` +/// +/// ```gleam +/// import gleam/list +/// > list.fold([1, 2, 3], 10, subtract) +/// 4 +/// ``` +/// +/// ```gleam +/// > 3 |> subtract(2) +/// 1 +/// ``` +/// +/// ```gleam +/// > 3 |> subtract(2, _) +/// -1 +/// ``` +/// +pub fn subtract(a: Int, b: Int) -> Int { + a - b +} + +/// Calculates the bitwise AND of its arguments. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "band") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_and") +pub fn bitwise_and(x: Int, y: Int) -> Int + +/// Calculates the bitwise NOT of its argument. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bnot") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_not") +pub fn bitwise_not(x: Int) -> Int + +/// Calculates the bitwise OR of its arguments. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bor") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_or") +pub fn bitwise_or(x: Int, y: Int) -> Int + +/// Calculates the bitwise XOR of its arguments. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bxor") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_exclusive_or") +pub fn bitwise_exclusive_or(x: Int, y: Int) -> Int + +/// Calculates the result of an arithmetic left bitshift. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bsl") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_left") +pub fn bitwise_shift_left(x: Int, y: Int) -> Int + +/// Calculates the result of an arithmetic right bitshift. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bsr") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_right") +pub fn bitwise_shift_right(x: Int, y: Int) -> Int |