builtins-llms.md

Full Docs per Module

Str

Utf8Problem : [ InvalidStartByte, UnexpectedEndOfSequence, ExpectedContinuation, OverlongEncoding, CodepointTooLarge, EncodesSurrogateHalf ]

is_empty : Str -> Bool

Description: Returns [Bool.true] if the string is empty, and [Bool.false] otherwise.

expect Str.is_empty("hi!") == Bool.false
expect Str.is_empty("") == Bool.true

concat : Str, Str -> Str

Description: Concatenates two strings together.

expect Str.concat("ab", "cd") == "abcd"
expect Str.concat("hello", "") == "hello"
expect Str.concat("", "") == ""

with_capacity : U64 -> Str

Description: Returns an empty string with the specified capacity pre-allocated. Use when building strings incrementally with [Str.concat] to avoid reallocations. Prefer over "" when concatenating. See [Str.reserve] for existing strings.

Str.with_capacity(45) |> Str.concat("Hello") |> Str.concat(", World!")

reserve : Str, U64 -> Str

Description: Increases a string's capacity by at least the given number of additional bytes, preventing reallocations during subsequent [Str.concat] calls. For empty strings, use [Str.with_capacity] instead.

greeting |> Str.reserve(21) |> Str.concat(", ") |> Str.concat(subject) |> Str.concat("!")

join_with : List Str, Str -> Str

Description: Combines a [List] of strings into a single string, with a separator string in between each.

expect Str.join_with(["one", "two", "three"], ", ") == "one, two, three"
expect Str.join_with(["1", "2", "3", "4"], ".") == "1.2.3.4"

split_on : Str, Str -> List Str

Description: Split a string around a separator.

Passing "" for the separator is not useful; it returns the original string wrapped in a [List].

expect Str.split_on("1,2,3", ",") == ["1","2","3"]
expect Str.split_on("1,2,3", "") == ["1,2,3"]

repeat : Str, U64 -> Str

Description: Repeats a string the given number of times.

expect Str.repeat("z", 3) == "zzz"
expect Str.repeat("na", 8) == "nananananananana"

Returns "" when given "" for the string or 0 for the count.

expect Str.repeat("", 10) == ""
expect Str.repeat("anything", 0) == ""

len : Str -> [LearnAboutStringsInRoc Str]

Description: A stub function to help people discover how they should handle this in Roc.

to_utf8 : Str -> List U8

Description: Returns a [List] of the string's [U8] UTF-8 code units. (To split the string into a [List] of smaller [Str] values instead of [U8] values, see [Str.split_on].)

expect Str.to_utf8("Roc") == [82, 111, 99]
expect Str.to_utf8("鹏") == [233, 185, 143]
expect Str.to_utf8("சி") == [224, 174, 154, 224, 174, 191]
expect Str.to_utf8("🐦") == [240, 159, 144, 166]

from_utf8 : List U8 -> Result Str [ BadUtf8 { problem : Utf8Problem, index : U64 } ]

Description: Converts a [List] of [U8] UTF-8 code units to a string.

Returns Err if the given bytes are invalid UTF-8, and returns Ok "" when given [].

expect Str.from_utf8([82, 111, 99]) == Ok("Roc")
expect Str.from_utf8([233, 185, 143]) == Ok("鹏")
expect Str.from_utf8([224, 174, 154, 224, 174, 191]) == Ok("சி")
expect Str.from_utf8([240, 159, 144, 166]) == Ok("🐦")
expect Str.from_utf8([]) == Ok("")
expect Str.from_utf8([255]) |> Result.is_err

from_utf8_lossy : List U8 -> Str

Description: Converts a [List] of [U8] UTF-8 code units to a string. Any grouping of invalid byte sequences are replaced with a single unicode replacement character '�'.

An invalid byte sequence is defined as

  • a 2-byte-sequence starting byte, followed by less than 1 continuation byte
  • a 3-byte-sequence starting byte, followed by less than 2 continuation bytes
  • a 4-byte-sequence starting byte, followed by less than 3 continuation bytes
  • an invalid codepoint from the surrogate pair block
  • an invalid codepoint greater than 0x110000 encoded as a 4-byte sequence
  • any valid codepoint encoded as an incorrect sequence, for instance a codepoint that should be a 2-byte sequence encoded as a 3- or 4-byte sequence
expect (Str.from_utf8_lossy [82, 111, 99, 240, 159, 144, 166]) == "Roc🐦"
expect (Str.from_utf8_lossy [82, 255, 99]) == "R�c"
expect (Str.from_utf8_lossy [82, 0xED, 0xA0, 0xBD, 99]) == "R�c"

from_utf16 : List U16 -> Result Str [ BadUtf16 { problem : Utf8Problem, index : U64 } ]

Description: Converts a [List] of [U16] UTF-16 (little-endian) code units to a string.

expect Str.from_utf16([82, 111, 99]) == Ok("Roc")
expect Str.from_utf16([0xb9a, 0xbbf]) == Ok("சி")
expect Str.from_utf16([0xd83d, 0xdc26]) == Ok("🐦")
expect Str.from_utf16([]) == Ok("")
# unpaired surrogates, first and second halves
expect Str.from_utf16([82, 0xd83d, 99]) |> Result.is_err
expect Str.from_utf16([82, 0xdc96, 99]) |> Result.is_err

from_utf16_lossy : List U16 -> Str

Description: Converts a [List] of [U16] UTF-16 (little-endian) code units to a string. Any unpaired surrogate code unit is replaced with a single unicode replacement character '�'.

expect Str.from_utf16_lossy([82, 111, 99, 0xd83d, 0xdc26]) == "Roc🐦"
expect Str.from_utf16_lossy([82, 0xdc96, 99]) == "R�c"

from_utf32 : List U32 -> Result Str [ BadUtf32 { problem : Utf8Problem, index : U64 } ]

from_utf32_lossy : List U32 -> Str

Description: Converts a [List] of [U32] UTF-32 code units to a string. Any invalid code points are replaced with a single unicode replacement character '�'.

expect Str.from_utf32_lossy([82, 111, 99, 0x1f426]) == "Roc🐦"
expect Str.from_utf32_lossy([82, 0x110000, 99]) == "R�c"

starts_with : Str, Str -> Bool

Description: Check if the given [Str] starts with a value.

expect Str.starts_with("ABC", "A") == Bool.true
expect Str.starts_with("ABC", "X") == Bool.false

ends_with : Str, Str -> Bool

Description: Check if the given [Str] ends with a value.

expect Str.ends_with("ABC", "C") == Bool.true
expect Str.ends_with("ABC", "X") == Bool.false

trim : Str -> Str

Description: Return the [Str] with all whitespace removed from both the beginning as well as the end.

expect Str.trim("   Hello      \n\n") == "Hello"

trim_start : Str -> Str

Description: Return the [Str] with all whitespace removed from the beginning.

expect Str.trim_start("   Hello      \n\n") == "Hello      \n\n"

trim_end : Str -> Str

Description: Return the [Str] with all whitespace removed from the end.

expect Str.trim_end("   Hello      \n\n") == "   Hello"

to_dec : Str -> Result Dec [InvalidNumStr]

Description: Encode a [Str] to a [Dec]. A [Dec] value is a 128-bit decimal fixed-point number.

expect Str.to_dec("10") == Ok(10dec)
expect Str.to_dec("-0.25") == Ok(-0.25dec)
expect Str.to_dec("not a number") == Err(InvalidNumStr)

to_f64 : Str -> Result F64 [InvalidNumStr]

Description: Encode a [Str] to a [F64]. A [F64] value is a 64-bit floating-point number and can be specified with a f64 suffix.

expect Str.to_f64("0.10") == Ok(0.10f64)
expect Str.to_f64("not a number") == Err(InvalidNumStr)

to_f32 : Str -> Result F32 [InvalidNumStr]

Description: Encode a [Str] to a [F32].A [F32] value is a 32-bit floating-point number and can be specified with a f32 suffix.

expect Str.to_f32("0.10") == Ok(0.10f32)
expect Str.to_f32("not a number") == Err(InvalidNumStr)

to_u128 : Str -> Result U128 [InvalidNumStr]

Description: Encode a [Str] to an unsigned [U128] integer. A [U128] value can hold numbers from 0 to 340_282_366_920_938_463_463_374_607_431_768_211_455 (over 340 undecillion). It can be specified with a u128 suffix.

expect Str.to_u128("1500") == Ok(1500u128)
expect Str.to_u128("0.1") == Err(InvalidNumStr)
expect Str.to_u128("-1") == Err(InvalidNumStr)
expect Str.to_u128("not a number") == Err(InvalidNumStr)

to_i128 : Str -> Result I128 [InvalidNumStr]

Description: Encode a [Str] to a signed [I128] integer. A [I128] value can hold numbers from -170_141_183_460_469_231_731_687_303_715_884_105_728 to 170_141_183_460_469_231_731_687_303_715_884_105_727. It can be specified with a i128 suffix.

expect Str.to_u128("1500") == Ok(1500i128)
expect Str.to_i128("-1") == Ok(-1i128)
expect Str.to_i128("0.1") == Err(InvalidNumStr)
expect Str.to_i128("not a number") == Err(InvalidNumStr)

to_u64 : Str -> Result U64 [InvalidNumStr]

Description: Encode a [Str] to an unsigned [U64] integer. A [U64] value can hold numbers from 0 to 18_446_744_073_709_551_615 (over 18 quintillion). It can be specified with a u64 suffix.

expect Str.to_u64("1500") == Ok(1500u64)
expect Str.to_u64("0.1") == Err(InvalidNumStr)
expect Str.to_u64("-1") == Err(InvalidNumStr)
expect Str.to_u64("not a number") == Err(InvalidNumStr)

to_i64 : Str -> Result I64 [InvalidNumStr]

Description: Encode a [Str] to a signed [I64] integer. A [I64] value can hold numbers from -9_223_372_036_854_775_808 to 9_223_372_036_854_775_807. It can be specified with a i64 suffix.

expect Str.to_i64("1500") == Ok(1500i64)
expect Str.to_i64("-1") == Ok(-1i64)
expect Str.to_i64("0.1") == Err(InvalidNumStr)
expect Str.to_i64("not a number") == Err(InvalidNumStr)

to_u32 : Str -> Result U32 [InvalidNumStr]

Description: Encode a [Str] to an unsigned [U32] integer. A [U32] value can hold numbers from 0 to 4_294_967_295 (over 4 billion). It can be specified with a u32 suffix.

expect Str.to_u32("1500") == Ok(1500u32)
expect Str.to_u32("0.1") == Err(InvalidNumStr)
expect Str.to_u32("-1") == Err(InvalidNumStr)
expect Str.to_u32("not a number") == Err(InvalidNumStr)

to_i32 : Str -> Result I32 [InvalidNumStr]

Description: Encode a [Str] to a signed [I32] integer. A [I32] value can hold numbers from -2_147_483_648 to 2_147_483_647. It can be specified with a i32 suffix.

expect Str.to_i32("1500") == Ok(1500i32)
expect Str.to_i32("-1") == Ok(-1i32)
expect Str.to_i32("0.1") == Err(InvalidNumStr)
expect Str.to_i32("not a number") == Err(InvalidNumStr)

to_u16 : Str -> Result U16 [InvalidNumStr]

Description: Encode a [Str] to an unsigned [U16] integer. A [U16] value can hold numbers from 0 to 65_535. It can be specified with a u16 suffix.

expect Str.to_u16("1500") == Ok(1500u16)
expect Str.to_u16("0.1") == Err(InvalidNumStr)
expect Str.to_u16("-1") == Err(InvalidNumStr)
expect Str.to_u16("not a number") == Err(InvalidNumStr)

to_i16 : Str -> Result I16 [InvalidNumStr]

Description: Encode a [Str] to a signed [I16] integer. A [I16] value can hold numbers from -32_768 to 32_767. It can be specified with a i16 suffix.

expect Str.to_i16("1500") == Ok(1500i16)
expect Str.to_i16("-1") == Ok(-1i16)
expect Str.to_i16("0.1") == Err(InvalidNumStr)
expect Str.to_i16("not a number") == Err(InvalidNumStr)

to_u8 : Str -> Result U8 [InvalidNumStr]

Description: Encode a [Str] to an unsigned [U8] integer. A [U8] value can hold numbers from 0 to 255. It can be specified with a u8 suffix.

expect Str.to_u8("250") == Ok(250u8)
expect Str.to_u8("-0.1") == Err(InvalidNumStr)
expect Str.to_u8("not a number") == Err(InvalidNumStr)
expect Str.to_u8("1500") == Err(InvalidNumStr)

to_i8 : Str -> Result I8 [InvalidNumStr]

Description: Encode a [Str] to a signed [I8] integer. A [I8] value can hold numbers from -128 to 127. It can be specified with a i8 suffix.

expect Str.to_i8("-15") == Ok(-15i8)
expect Str.to_i8("150.00") == Err(InvalidNumStr)
expect Str.to_i8("not a number") == Err(InvalidNumStr)

count_utf8_bytes : Str -> U64

Description: Gives the number of bytes in a [Str] value.

expect Str.count_utf8_bytes("Hello World") == 11

replace_each : Str, Str, Str -> Str

Description: Returns the given [Str] with each occurrence of a substring replaced. If the substring is not found, returns the original string.

expect Str.replace_each("foo/bar/baz", "/", "_") == "foo_bar_baz"
expect Str.replace_each("not here", "/", "_") == "not here"

replace_first : Str, Str, Str -> Str

Description: Returns the given [Str] with the first occurrence of a substring replaced. If the substring is not found, returns the original string.

expect Str.replace_first("foo/bar/baz", "/", "_") == "foo_bar/baz"
expect Str.replace_first("no slashes here", "/", "_") == "no slashes here"

replace_last : Str, Str, Str -> Str

Description: Returns the given [Str] with the last occurrence of a substring replaced. If the substring is not found, returns the original string.

expect Str.replace_last("foo/bar/baz", "/", "_") == "foo/bar_baz"
expect Str.replace_last("no slashes here", "/", "_") == "no slashes here"

split_first : Str, Str -> Result { before : Str, after : Str } [NotFound]

Description: Returns the given [Str] before the first occurrence of a delimiter, as well as the rest of the string after that occurrence. Returns [Err NotFound] if the delimiter is not found.

expect Str.split_first("foo/bar/baz", "/") == Ok({ before: "foo", after: "bar/baz" })
expect Str.split_first("no slashes here", "/") == Err(NotFound)

split_last : Str, Str -> Result { before : Str, after : Str } [NotFound]

Description: Returns the given [Str] before the last occurrence of a delimiter, as well as the rest of the string after that occurrence. Returns [Err NotFound] if the delimiter is not found.

expect Str.split_last("foo/bar/baz", "/") == Ok({ before: "foo/bar", after: "baz" })
expect Str.split_last("no slashes here", "/") == Err(NotFound)

walk_utf8_with_index : Str, state, (state, U8, U64 -> state) -> state

Description: Walks over the UTF-8 bytes of the given [Str] and calls a function to update state for each byte. The index for that byte in the string is provided to the update function.

f : List U8, U8, U64 -> List U8
f = \state, byte, _ -> List.append(state, byte)
expect Str.walk_utf8_with_index("ABC", [], f) == [65, 66, 67]

walk_utf8 : Str, state, (state, U8 -> state) -> state

Description: Walks over the UTF-8 bytes of the given [Str] and calls a function to update state for each byte.

sum_of_utf8_bytes =
    Str.walk_utf8("Hello, World!", 0, (\total, byte ->
        total + byte
    ))

expect sum_of_utf8_bytes == 105

release_excess_capacity : Str -> Str

Description: Shrink the memory footprint of a str such that its capacity and length are equal. Note: This will also convert seamless slices to regular lists.

with_prefix : Str, Str -> Str

Description: Adds a prefix to the given [Str].

expect Str.with_prefix("Awesome", "Roc") == "RocAwesome"

contains : Str, Str -> Bool

Description: Determines whether or not the first Str contains the second.

expect Str.contains("foobarbaz", "bar")
expect !Str.contains("apple", "orange")
expect Str.contains("anything", "")

drop_prefix : Str, Str -> Str

Description: Drops the given prefix [Str] from the start of a [Str] If the prefix is not found, returns the original string.

expect Str.drop_prefix("bar", "foo") == "bar"
expect Str.drop_prefix("foobar", "foo") == "bar"

drop_suffix : Str, Str -> Str

Description: Drops the given suffix [Str] from the end of a [Str] If the suffix is not found, returns the original string.

expect Str.drop_suffix("bar", "foo") == "bar"
expect Str.drop_suffix("barfoo", "foo") == "bar"

with_ascii_lowercased : Str -> Str

Description: Lowercases ASCII characters only; non-ASCII left unchanged. For Unicode capitalization, use the unicode package. See [Str.caseless_ascii_equals] for case-insensitive comparison.

expect Str.with_ascii_lowercased("CAFÉ") == "cafÉ"

with_ascii_uppercased : Str -> Str

Description: Uppercases ASCII characters only; non-ASCII left unchanged. For Unicode capitalization, use the unicode package. See [Str.caseless_ascii_equals] for case-insensitive comparison.

expect Str.with_ascii_uppercased("café") == "CAFé"

caseless_ascii_equals : Str, Str -> Bool

Description: Case-insensitive comparison for ASCII characters only; non-ASCII must match exactly. See [Str.with_ascii_uppercased] and [Str.with_ascii_lowercased] for conversion.

expect Str.caseless_ascii_equals("café", "CAFé")
expect !Str.caseless_ascii_equals("café", "CAFÉ")  # é ≠ É (non-ASCII)

Num

Num a represents either an [Int] or [Frac]. Aliases: Int a = Num (Integer a), Frac a = Num (Fraction a).

Untyped literals default to [I64] (integers) or [Dec] (decimals). Use suffixes for specific types: 215u8, 76.4f32, 123.45dec.

Int Types

Signed ([I8]-[I128]) can be negative; unsigned ([U8]-[U128]) cannot. Overflow crashes.

Type Bytes Range
I8/U8 1 -128..127 / 0..255
I16/U16 2 -32768..32767 / 0..65535
I32/U32 4 ±2.1B / 0..4.3B
I64/U64 8 ±9.2×10¹⁸ / 0..1.8×10¹⁹
I128/U128 16 ±1.7×10³⁸ / 0..3.4×10³⁸

Frac Types

  • [Dec]: 128-bit fixed-point, 18 decimal places. 0.1 + 0.2 == 0.3 (precise). Default for decimals.
  • [F32]/[F64]: Floating-point. Faster but imprecise: 0.1f64 + 0.2 != 0.3. Has infinity/NaN.

Special float values (IEEE-754): ∞ (pos/0.0), -∞ (neg/0.0), NaN (0.0/0.0). Check with #is_nan, #is_finite, #is_infinite.

Performance: Dec add/sub similar to F64; Dec mul ~15x slower, div ~55x slower, trig ~2-4x slower. Use F64/F32 for performance-critical graphics/trig.

e : Frac *

Description: Euler's number (e)

pi : Frac *

Description: Archimedes' constant (π)

tau : Frac *

Description: Circle constant (τ)

to_str : Num * -> Str

Description: Convert a number to a [Str].

Num.to_str(42)

Only [Frac] values will include a decimal point, and they will always include one.

Num.to_str(4.2)
Num.to_str(4.0)

When this function is given a non-finite [F64] or [F32] value, the returned string will be "NaN", "∞", or "-∞".

int_cast : Int a -> Int b

Description: Convert an [Int] to a new [Int] of the expected type:

# Casts a U8 to a U16
x : U16
x = Num.int_cast(255u8)

In the case of downsizing, information is lost:

# returns 0, as the bits were truncated.
x : U8
x = Num.int_cast(256u16)

compare : Num a, Num a -> [ LT, EQ, GT ]

is_lt : Num a, Num a -> Bool

Description: Returns Bool.true if the first number is less than the second.

a < b is shorthand for Num.is_lt(a, b).

If either argument is NaN, returns Bool.false no matter what. (NaN is defined to be unordered.)

5
    |> Num.is_lt 6

is_gt : Num a, Num a -> Bool

Description: Returns Bool.true if the first number is greater than the second.

a > b is shorthand for Num.is_gt a b.

If either argument is NaN, returns Bool.false no matter what. (NaN is defined to be unordered.)

Num.is_gt(6, 5)

is_lte : Num a, Num a -> Bool

Description: Returns Bool.true if the first number is less than or equal to the second.

a <= b is shorthand for Num.is_lte(a, b).

If either argument is NaN, returns Bool.false no matter what. (NaN is defined to be unordered.)

is_gte : Num a, Num a -> Bool

Description: Returns Bool.true if the first number is greater than or equal to the second.

a >= b is shorthand for Num.is_gte(a, b).

If either argument is NaN, returns Bool.false no matter what. (NaN is defined to be unordered.)

is_approx_eq : Frac a, Frac a, { rtol ? Frac a, atol ? Frac a } -> Bool

Description: Returns Bool.true if the first number and second number are within a specific threshold

A specific relative and absolute tolerance can be provided to change the threshold

This function is symmetric: Num.is_approx_eq(a, b) == Num.is_approx_eq(b, a)

If either argument is NaN, returns Bool.false no matter what. (NaN is defined to be unordered.)

is_zero : Num a -> Bool

Description: Returns Bool.true if the number is 0, and Bool.false otherwise.

is_even : Int a -> Bool

Description: A number is even if dividing it by 2 gives a remainder of 0.

Examples of even numbers: 0, 2, 4, 6, 8, -2, -4, -6, -8

is_odd : Int a -> Bool

Description: A number is odd if dividing it by 2 gives a remainder of 1.

Examples of odd numbers: 1, 3, 5, 7, -1, -3, -5, -7

is_positive : Num a -> Bool

Description: Positive numbers are greater than 0.

is_negative : Num a -> Bool

Description: Negative numbers are less than 0.

to_frac : Num * -> Frac *

is_nan : Frac * -> Bool

Description: Returns Bool.true if the [Frac] is not a number as defined by IEEE-754

Num.is_nan(0 / 0)

is_infinite : Frac * -> Bool

Description: Returns Bool.true if the [Frac] is positive or negative infinity as defined by IEEE-754

Num.is_infinite(1 / 0)

Num.is_infinite(-1 / 0)

is_finite : Frac * -> Bool

Description: Returns Bool.true if the [Frac] is not an infinity as defined by IEEE-754

Num.is_finite(42)

abs : Num a -> Num a

Description: Returns the absolute value of the number.

  • For a positive number, returns the same number.
  • For a negative number, returns the same number except positive.
  • For zero, returns zero.
Num.abs(4)

Num.abs(-2.5)

Num.abs(0)

Num.abs(0.0)

This is safe to use with any [Frac], but it can cause overflow when used with certain [Int] values.

For example, calling #Num.abs on the lowest value of a signed integer (such as [Num.min_i64] or [Num.min_i32]) will cause overflow. This is because, for any given size of signed integer (32-bit, 64-bit, etc.) its negated lowest value turns out to be 1 higher than the highest value it can represent. (For this reason, calling [Num.neg] on the lowest signed value will also cause overflow.)

Calling this on an unsigned integer (like [U32] or [U64]) never does anything.

abs_diff : Num a, Num a -> Num a

Description: Returns the absolute difference between two numbers.

Num.abs_diff(5, 3)

Num.abs_diff(-3, 5)

Num.abs_diff(3.0, 5.0)

If the answer to this operation can't fit in the return value (e.g. an [I8] answer that's higher than 127 or lower than -128), the result is an overflow. For [F64] and [F32], overflow results in an answer of either ∞ or -∞. For all other number types, overflow results in a panic.

neg : Num a -> Num a

Description: Returns a negative number when given a positive one, and vice versa.

Num.neg(5)

Num.neg(-2.5)

Num.neg(0)

Num.neg(0.0)

!! Num.neg is not completely implemented for all types in all contexts, see github.com/roc-lang/roc/issues/6959 You can use \some_num -> 0 - some_num as a workaround.

This is safe to use with any [Frac], but it can cause overflow when used with certain [Int] values.

For example, calling #Num.neg on the lowest value of a signed integer (such as [Num.min_i64] or [Num.min_i32]) will cause overflow. This is because, for any given size of signed integer (32-bit, 64-bit, etc.) its negated lowest value turns out to be 1 higher than the highest value it can represent. (For this reason, calling #Num.abs on the lowest signed value will also cause overflow.)

Additionally, calling #Num.neg on any unsigned integer (such as any [U64] or [U32] value) other than zero will cause overflow.

(It will never crash when given a [Frac], however, because of how floating point numbers represent positive and negative numbers.)

add : Num a, Num a -> Num a

Description: Adds two numbers of the same type.

(To add an [Int] and a [Frac], first convert one so that they both have the same type. There are functions in this module that can convert both [Int] to [Frac] and the other way around.)

a + b is shorthand for Num.add(a, b).

5 + 7

Num.add(5, 7)

Num.add can be convenient in pipelines.

Frac.pi
    |> Num.add(1.0)

If the answer to this operation can't fit in the return value (e.g. an [I8] answer that's higher than 127 or lower than -128), the result is an overflow. For [F64] and [F32], overflow results in an answer of either ∞ or -∞. For all other number types, overflow results in a panic.

sub : Num a, Num a -> Num a

Description: Subtracts two numbers of the same type.

(To subtract an [Int] and a [Frac], first convert one so that they both have the same type. There are functions in this module that can convert both [Int] to [Frac] and the other way around.)

a - b is shorthand for Num.sub(a, b).

7 - 5

Num.sub(7, 5)

Num.sub can be convenient in pipelines.

Frac.pi
    |> Num.sub(2.0)

If the answer to this operation can't fit in the return value (e.g. an [I8] answer that's higher than 127 or lower than -128), the result is an overflow. For [F64] and [F32], overflow results in an answer of either ∞ or -∞. For all other number types, overflow results in a panic.

mul : Num a, Num a -> Num a

Description: Multiplies two numbers of the same type.

(To multiply an [Int] and a [Frac], first convert one so that they both have the same type. There are functions in this module that can convert both [Int] to [Frac] and the other way around.)

a * b is shorthand for Num.mul(a, b).

5 * 7

Num.mul(5, 7)

Num.mul can be convenient in pipelines.

Frac.pi
    |> Num.mul(2.0)

If the answer to this operation can't fit in the return value (e.g. an [I8] answer that's higher than 127 or lower than -128), the result is an overflow. For [F64] and [F32], overflow results in an answer of either ∞ or -∞. For all other number types, overflow results in a panic.

min : Num a, Num a -> Num a

Description: Obtains the smaller between two numbers of the same type.

Num.min(100, 0)

Num.min(3.0, -3.0)

max : Num a, Num a -> Num a

Description: Obtains the greater between two numbers of the same type.

Num.max(100, 0)

Num.max(3.0, -3.0)

sin : Frac a -> Frac a

cos : Frac a -> Frac a

tan : Frac a -> Frac a

asin : Frac a -> Frac a

acos : Frac a -> Frac a

atan : Frac a -> Frac a

sqrt : Frac a -> Frac a

Description: Returns an approximation of the absolute value of a [Frac]'s square root.

The square root of a negative number is an irrational number, and [Frac] only supports rational numbers. As such, you should make sure never to pass this function a negative number! Calling [sqrt] on a negative [Dec] will cause a panic.

Calling [sqrt] on [F32] and [F64] values follows these rules:

  • Passing a negative [F64] or [F32] returns NaN.
  • Passing NaN or -∞ also returns NaN.
  • Passing ∞ returns ∞.

These rules come from the IEEE-754 floating point standard. Because almost all modern processors are built to this standard, deviating from these rules has a significant performance cost! Since the most common reason to choose [F64] or [F32] over [Dec] is access to hardware-accelerated performance, Roc follows these rules exactly.

Num.sqrt(4.0)

Num.sqrt(1.5)

Num.sqrt(0.0)

Num.sqrt(-4.0f64)

sqrt_checked : Frac a -> Result (Frac a) [SqrtOfNegative]

log : Frac a -> Frac a

Description: Natural logarithm

log_checked : Frac a -> Result (Frac a) [LogNeedsPositive]

div : Frac a, Frac a -> Frac a

Description: Divides one [Frac] by another.

a / b is shorthand for Num.div(a, b).

Division by zero is undefined in mathematics. As such, you should make sure never to pass zero as the denominator to this function! Calling [div] on a [Dec] denominator of zero will cause a panic.

Calling [div] on [F32] and [F64] values follows these rules:

  • Dividing a positive [F64] or [F32] by zero returns ∞.
  • Dividing a negative [F64] or [F32] by zero returns -∞.
  • Dividing a zero [F64] or [F32] by zero returns NaN.

These rules come from the IEEE-754 floating point standard. Because almost all modern processors are built to this standard, deviating from these rules has a significant performance cost! Since the most common reason to choose [F64] or [F32] over [Dec] is access to hardware-accelerated performance, Roc follows these rules exactly.

To divide an [Int] and a [Frac], first convert the [Int] to a [Frac] using one of the functions in this module like #to_dec.

5.0 / 7.0

Num.div(5, 7)

Num.div can be convenient in pipelines.

Num.pi
    |> Num.div (2.0)

div_checked : Frac a, Frac a -> Result (Frac a) [DivByZero]

div_ceil : Int a, Int a -> Int a

div_ceil_checked : Int a, Int a -> Result (Int a) [DivByZero]

div_trunc : Int a, Int a -> Int a

Description: Divides two integers, truncating the result towards zero.

a // b is shorthand for Num.div_trunc(a, b).

Division by zero is undefined in mathematics. As such, you should make sure never to pass zero as the denominator to this function! If you do, it will crash.

5 // 7

Num.div_trunc(5, 7)

8 // -3

Num.div_trunc(8, -3)

div_trunc_checked : Int a, Int a -> Result (Int a) [DivByZero]

rem : Int a, Int a -> Int a

Description: Obtains the remainder (truncating modulo) from the division of two integers.

a % b is shorthand for Num.rem(a, b).

5 % 7

Num.rem(5, 7)

-8 % -3

Num.rem(-8, -3)

rem_checked : Int a, Int a -> Result (Int a) [DivByZero]

is_multiple_of : Int a, Int a -> Bool

bitwise_and : Int a, Int a -> Int a

Description: Does a "bitwise and". Each bit of the output is 1 if the corresponding bit of x AND of y is 1, otherwise it's 0.

bitwise_xor : Int a, Int a -> Int a

Description: Does a "bitwise exclusive or". Each bit of the output is the same as the corresponding bit in x if that bit in y is 0, and it's the complement of the bit in x if that bit in y is 1.

bitwise_or : Int a, Int a -> Int a

Description: Does a "bitwise or". Each bit of the output is 0 if the corresponding bit of x OR of y is 0, otherwise it's 1.

bitwise_not : Int a -> Int a

Description: Returns the complement of x - the number you get by switching each 1 for a 0 and each 0 for a 1. This is the same as -x - 1.

shift_left_by : Int a, U8 -> Int a

Description: Bitwise left shift of a number by another

The least significant bits always become 0. This means that shifting left is like multiplying by factors of two for unsigned integers.

shift_left_by(0b0000_0011, 2) == 0b0000_1100

0b0000_0101 |> shift_left_by(2) == 0b0001_0100

In some languages shift_left_by is implemented as a binary operator <<.

shift_right_by : Int a, U8 -> Int a

Description: Bitwise arithmetic shift of a number by another

The most significant bits are copied from the current.

shift_right_by(0b0000_1100, 2) == 0b0000_0011

0b0001_0100 |> shift_right_by(2) == 0b0000_0101

0b1001_0000 |> shift_right_by(2) == 0b1110_0100

In some languages shift_right_by is implemented as a binary operator >>>.

shift_right_zf_by : Int a, U8 -> Int a

Description: Bitwise logical right shift of a number by another

The most significant bits always become 0. This means that shifting right is like dividing by factors of two for unsigned integers.

shift_right_zf_by(0b0010_1000, 2) == 0b0000_1010

0b0010_1000 |> shift_right_zf_by(2) == 0b0000_1010

0b1001_0000 |> shift_right_zf_by(2) == 0b0010_0100

In some languages shift_right_zf_by is implemented as a binary operator >>.

round : Frac * -> Int *

Description: Round off the given fraction to the nearest integer.

floor : Frac * -> Int *

ceiling : Frac * -> Int *

pow : Frac a, Frac a -> Frac a

Description: Raises a [Frac] to the power of another [Frac].

For an [Int] alternative to this function, see [Num.pow_int]

pow_int : Int a, Int a -> Int a

Description: Raises an integer to the power of another, by multiplying the integer by itself the given number of times.

This process is known as exponentiation by squaring.

For a [Frac] alternative to this function, which supports negative exponents, see #Num.pow.

Warning

It is very easy for this function to produce an answer so large it causes an overflow.

count_leading_zero_bits : Int a -> U8

Description: Counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer.

Num.count_leading_zero_bits(0b0001_1100u8)

3

Num.count_leading_zero_bits(0b0000_0000u8)

8

count_trailing_zero_bits : Int a -> U8

Description: Counts the number of least-significant (trailing in a big-Endian sense) zeroes in an integer.

Num.count_trailing_zero_bits(0b0001_1100u8)

2

Num.count_trailing_zero_bits(0b0000_0000u8)

8

count_one_bits : Int a -> U8

Description: Counts the number of set bits in an integer.

Num.count_one_bits(0b0001_1100u8)

3

Num.count_one_bits(0b0000_0000u8)

0

add_wrap : Int range, Int range -> Int range

add_saturated : Num a, Num a -> Num a

Description: Adds two numbers, clamping on the maximum representable number rather than overflowing.

This is the same as [Num.add] except for the saturating behavior if the addition is to overflow. For example, if x : U8 is 200 and y : U8 is 100, add_saturated x y will yield 255, the maximum value of a U8.

add_checked : Num a, Num a -> Result (Num a) [Overflow]

Description: Adds two numbers and checks for overflow.

This is the same as [Num.add] except if the operation overflows, instead of panicking or returning ∞ or -∞, it will return Err Overflow.

sub_wrap : Int range, Int range -> Int range

sub_saturated : Num a, Num a -> Num a

Description: Subtracts two numbers, clamping on the minimum representable number rather than overflowing.

This is the same as [Num.sub] except for the saturating behavior if the subtraction is to overflow. For example, if x : U8 is 10 and y : U8 is 20, sub_saturated x y will yield 0, the minimum value of a U8.

sub_checked : Num a, Num a -> Result (Num a) [Overflow]

Description: Subtracts two numbers and checks for overflow.

This is the same as [Num.sub] except if the operation overflows, instead of panicking or returning ∞ or -∞, it will return Err Overflow.

mul_wrap : Int range, Int range -> Int range

mul_saturated : Num a, Num a -> Num a

Description: Multiplies two numbers, clamping on the maximum representable number rather than overflowing.

This is the same as [Num.mul] except for the saturating behavior if the addition is to overflow.

mul_checked : Num a, Num a -> Result (Num a) [Overflow]

Description: Multiplies two numbers and checks for overflow.

This is the same as [Num.mul] except if the operation overflows, instead of panicking or returning ∞ or -∞, it will return Err Overflow.

Integer Type Bounds

Type min max
I8 -128 127
I16 -32_768 32_767
I32 -2_147_483_648 2_147_483_647
I64 -9_223_372_036_854_775_808 9_223_372_036_854_775_807
I128 -170_141_183_460_469_231_731_687_303_715_884_105_728 170_141_183_460_469_231_731_687_303_715_884_105_727
U8 0 255
U16 0 65_535
U32 0 4_294_967_295
U64 0 18_446_744_073_709_551_615
U128 0 340_282_366_920_938_463_463_374_607_431_768_211_455

Functions: min_i8, max_i8, min_u8, max_u8, etc. for all integer types. Also: min_f32, max_f32, min_f64, max_f64 for float bounds.

Note: For signed types, |Num.abs(min_iN)| > max_iN, so Num.abs(min_iN) will overflow.

to_i8 : Int * -> I8

Description: Converts an [Int] to an [I8]. If the given number can't be precisely represented in an [I8], the returned number may be different from the given number.

to_i16 : Int * -> I16

to_i32 : Int * -> I32

to_i64 : Int * -> I64

to_i128 : Int * -> I128

to_u8 : Int * -> U8

to_u16 : Int * -> U16

to_u32 : Int * -> U32

to_u64 : Int * -> U64

to_u128 : Int * -> U128

to_f32 : Num * -> F32

Description: Converts a [Num] to an [F32]. If the given number can't be precisely represented in an [F32], the returned number may be different from the given number.

to_f64 : Num * -> F64

Description: Converts a [Num] to an [F64]. If the given number can't be precisely represented in an [F64], the returned number may be different from the given number.

to_i8_checked : Int * -> Result I8 [OutOfBounds]

Description: Converts a [Int] to an [I8]. If the given integer can't be precisely represented in an [I8], returns Err OutOfBounds.

to_i16_checked : Int * -> Result I16 [OutOfBounds]

to_i32_checked : Int * -> Result I32 [OutOfBounds]

to_i64_checked : Int * -> Result I64 [OutOfBounds]

to_i128_checked : Int * -> Result I128 [OutOfBounds]

to_u8_checked : Int * -> Result U8 [OutOfBounds]

to_u16_checked : Int * -> Result U16 [OutOfBounds]

to_u32_checked : Int * -> Result U32 [OutOfBounds]

to_u64_checked : Int * -> Result U64 [OutOfBounds]

to_u128_checked : Int * -> Result U128 [OutOfBounds]

to_f32_checked : Num * -> Result F32 [OutOfBounds]

to_f64_checked : Num * -> Result F64 [OutOfBounds]

without_decimal_point : Dec -> I128

Description: Turns a [Dec] into its [I128] representation by removing the decimal point. This is equivalent to multiplying the [Dec] by 10^18.

with_decimal_point : I128 -> Dec

Description: Turns a [I128] into the coresponding [Dec] by adding the decimal point. This is equivalent to dividing the [I128] by 10^18.

f32_to_parts : F32 -> { sign : Bool, exponent : U8, fraction : U32 }

Description: Splits a [F32] into its components according to IEEE 754 standard.

This function is deprecated due to common pitfalls when working with float components using Roc’s fixed-size integer types. Please use [Num.f32_to_bits] instead and extract the IEEE 754 parts manually from the resulting [U32].

f64_to_parts : F64 -> { sign : Bool, exponent : U16, fraction : U64 }

Description: Splits a [F64] into its components according to IEEE 754 standard.

This function is deprecated due to common pitfalls when working with float components using Roc’s fixed-size integer types. Please use [Num.f64_to_bits] instead and extract the IEEE 754 parts manually from the resulting [U64].

f32_from_parts : { sign : Bool, exponent : U8, fraction : U32 } -> F32

Description: Combine parts of a [F32] according to IEEE 754 standard. The fraction should not be bigger than 0x007F_FFFF, any bigger value will be truncated.

This function is deprecated due to common pitfalls when working with float components using Roc’s fixed-size integer types. Please combine the IEEE 754 parts manually into a [U32] and use [Num.f32_from_bits] to create the [F32] instead.

f64_from_parts : { sign : Bool, exponent : U16, fraction : U64 } -> F64

Description: Combine parts of a [F64] according to IEEE 754 standard. The fraction should not be bigger than 0x000F_FFFF_FFFF_FFFF, any bigger value will be truncated. The exponent should not be bigger than 0x07FF, any bigger value will be truncated.

This function is deprecated due to common pitfalls when working with float components using Roc’s fixed-size integer types. Please combine the IEEE 754 parts manually into a [U64] and use [Num.f64_from_bits] to create the [F64] instead.

f32_to_bits : F32 -> U32

Description: Returns a [U32] containing the raw bits of a [F32], as defined by the IEEE 754 standard.

f64_to_bits : F64 -> U64

Description: Returns a [U64] containing the raw bits of a [F64], as defined by the IEEE 754 standard.

dec_to_bits : Dec -> U128

Description: Returns a [U128] containing the raw bits of a [Dec], which corresponds to the raw bits of its [I128] representation.

f32_from_bits : U32 -> F32

Description: Interprets a [U32] as the binary representation of a 32-bit floating-point value according to the IEEE 754 standard and returns the corresponding [F32].

f64_from_bits : U64 -> F64

Description: Interprets a [U64] as the binary representation of a 64-bit floating-point value according to the IEEE 754 standard and returns the corresponding [F64].

dec_from_bits : U128 -> Dec

Description: Interprets a [U128] as the raw bits of the internal [I128] representation of a fixed-point decimal value and returns the corresponding [Dec].

from_bool : Bool -> Num *

Description: Convert a Bool to a Num

expect Num.from_bool(Bool.true) == 1
expect Num.from_bool(Bool.false) == 0

nan_f32 : F32

Description: The value for not-a-number for a [F32] according to the IEEE 754 standard.

nan_f64 : F64

Description: The value for not-a-number for a [F64] according to the IEEE 754 standard.

infinity_f32 : F32

Description: The value for infinity for a [F32] according to the IEEE 754 standard.

infinity_f64 : F64

Description: The value for infinity for a [F64] according to the IEEE 754 standard.

Bool

Eq : implements is_eq : a, a -> Bool where a implements Eq

Description: Defines a type that can be compared for total equality.

Total equality means that all values of the type can be compared to each other, and two values a, b are identical if and only if is_eq(a, b) is Bool.true.

Not all types support total equality. For example, F32 and F64 can be a NaN (Not a Number), and the IEEE-754 floating point standard specifies that two NaNs are not equal.

Description: Represents the boolean true and false using an opaque type. Bool implements the Eq ability.

true : Bool

Description: The boolean true value.

false : Bool

Description: The boolean false value.

not : Bool -> Bool

Description: Returns Bool.false when given Bool.true, and vice versa. This is equivalent to the logic NOT gate. The operator ! can also be used as shorthand for Bool.not.

expect Bool.not(Bool.false) == Bool.true
expect !Bool.false == Bool.true

is_not_eq : a, a -> Bool where a implements Eq

Description: This will call the function Bool.is_eq on the inputs, and then Bool.not on the result. The is equivalent to the logic XOR gate. The infix operator != can also be used as shorthand for Bool.is_not_eq.

Note that is_not_eq does not accept arguments whose types contain functions.

expect Bool.is_not_eq(Bool.false, Bool.true) == Bool.true
expect (Bool.false != Bool.false) == Bool.false
expect "Apples" != "Oranges"

Result

Result : [ Ok ok, Err err ]

Description: The result of an operation that could fail: either the operation went okay, or else there was an error of some sort.

is_ok : Result ok err -> Bool

Description: Returns Bool.true if the result indicates a success, else returns Bool.false.

Result.is_ok(Ok(5))

is_err : Result ok err -> Bool

Description: Returns Bool.true if the result indicates a failure, else returns Bool.false.

Result.is_err(Err("uh oh"))

with_default : Result ok err, ok -> ok

Description: If the result is Ok, returns the value it holds. Otherwise, returns the given default value.

Note: This function should be used sparingly, because it hides that an error happened, which will make debugging harder. Prefer using ? to forward errors or handle them explicitly with when.

Result.with_default(Err("uh oh"), 42) # = 42

Result.with_default(Ok(7), 42) # = 7

map_ok : Result a err, (a -> b) -> Result b err

Description: If the result is Ok, transforms the value it holds by running a conversion function on it. Then returns a new Ok holding the transformed value. If the result is Err, this has no effect. Use [map_err] to transform an Err.

Result.map_ok(Ok(12), Num.neg) # = Ok(-12)

Result.map_ok(Err("yipes!"), Num.neg) # = Err("yipes!")

Functions like map are common in Roc; see for example [List.map], Set.map, and Dict.map.

map_err : Result ok a, (a -> b) -> Result ok b

Description: If the result is Err, transforms the value it holds by running a conversion function on it. Then returns a new Err holding the transformed value. If the result is Ok, this has no effect. Use [map_ok] to transform an Ok.

List.last([]) |> Result.map_err(|_| ProvidedListIsEmpty) # = Err(ProvidedListIsEmpty)

List.last([4]) |> Result.map_err(|_| ProvidedListIsEmpty) # = Ok(4)

on_err : Result a err, (err -> Result a other_err) -> Result a other_err

Description: If the result is Err, transforms the entire result by running a conversion function on the value the Err holds. Then returns that new result. If the result is Ok, this has no effect. Use ? or [try] to transform an Ok.

Result.on_err(Ok(10), Str.to_u64) # = Ok(10)

Result.on_err(Err("42"), Str.to_u64) # = Ok(42)

Result.on_err(Err("string"), Str.to_u64) # = Err(InvalidNumStr)

on_err! : Result a err, (err => Result a other_err) => Result a other_err

Description: Like [on_err], but it allows the transformation function to produce effects.

Result.on_err(
    Err("missing user"),
    |msg|
        Stdout.line!("ERROR: ${msg}")?
        Err(msg)
)

map_both : Result ok1 err1, (ok1 -> ok2), (err1 -> err2) -> Result ok2 err2

Description: Maps both the Ok and Err values of a Result to new values.

map2 : Result a err, Result b err, (a, b -> c) -> Result c err

Description: Maps the Ok values of two Results to a new value using a given transformation, or returns the first Err value encountered.

try : Result a err, (a -> Result b err) -> Result b err

Description: If the result is Ok, transforms the entire result by running a conversion function on the value the Ok holds. Then returns that new result. If the result is Err, this has no effect.

We recommend using ? instead of try, it makes the code easier to read.

Result.try(Ok(-1), (|num| if num < 0 then Err("negative!") else Ok(-num))) # = Err("negative!")

Result.try(Err("yipes!"), (|num| -> if num < 0 then Err("negative!") else Ok(-num))) # = Err("yipes!")

List

is_empty : List * -> Bool

Description: Check if the list is empty.

List.is_empty([1, 2, 3])

List.is_empty([])

get : List a, U64 -> Result a [OutOfBounds]

Description: Returns an element from a list at the given index.

Returns Err OutOfBounds if the given index exceeds the List's length

expect List.get([100, 200, 300], 1) == Ok(200)
expect List.get([100, 200, 300], 5) == Err(OutOfBounds)

replace : List a, U64, a -> { list : List a, value : a }

set : List a, U64, a -> List a

Description: Replaces the element at the given index with a replacement.

List.set(["a", "b", "c"], 1, "B")

If the given index is outside the bounds of the list, returns the original list unmodified.

To drop the element at a given index, instead of replacing it, see [List.drop_at].

update : List a, U64, (a -> a) -> List a

Description: Updates the element at the given index with the given function.

List.update([1, 2, 3], 1, (|x| x + 1))

If the given index is outside the bounds of the list, returns the original list unmodified.

To replace the element at a given index, instead of updating based on the current value, see [List.set] and [List.replace]

append : List a, a -> List a

Description: Add a single element to the end of a list.

List.append([1, 2, 3], 4)

[0, 1, 2]
    |> List.append(3)

append_if_ok : List a, Result a * -> List a

Description: If the given [Result] is Ok, add it to the end of a list. Otherwise, return the list unmodified.

List.append_if_ok([1, 2, 3], Ok(4))

[0, 1, 2]
    |> List.append_if_ok(Err(3))

prepend : List a, a -> List a

Description: Add a single element to the beginning of a list.

List.prepend([1, 2, 3], 0)

[2, 3, 4]
    |> List.prepend(1)

prepend_if_ok : List a, Result a * -> List a

Description: If the given [Result] is Ok, add it to the beginning of a list. Otherwise, return the list unmodified.

List.prepend([1, 2, 3], Ok(0))

[2, 3, 4]
    |> List.prepend(Err(1))

len : List * -> U64

Description: Returns the length of the list - the number of elements it contains.

One [List] can store up to Num.max_i64 elements on 64-bit targets and Num.max_i32 on 32-bit targets like wasm. This means the #U64 this function returns can always be safely converted to #I64 or #I32, depending on the target.

with_capacity : U64 -> List *

Description: Create a list with space for at least capacity elements

reserve : List a, U64 -> List a

Description: Enlarge the list for at least capacity additional elements

release_excess_capacity : List a -> List a

Description: Shrink the memory footprint of a list such that it's capacity and length are equal. Note: This will also convert seamless slices to regular lists.

concat : List a, List a -> List a

Description: Put two lists together.

List.concat([1, 2, 3], [4, 5])

[0, 1, 2]
    |> List.concat([3, 4])

last : List a -> Result a [ListWasEmpty]

Description: Returns the last element in the list, or ListWasEmpty if it was empty.

expect List.last([1, 2, 3]) == Ok(3)
expect List.last([]) == Err(ListWasEmpty)

single : a -> List a

Description: A list with a single element in it.

This is useful in pipelines, like so:

websites =
    Str.concat(domain, ".com")
        |> List.single

repeat : a, U64 -> List a

Description: Returns a list with the given length, where every element is the given value.

reverse : List a -> List a

Description: Returns the list with its elements reversed.

expect List.reverse([1, 2, 3]) == [3, 2, 1]

join : List (List a) -> List a

Description: Join the given lists together into one list.

expect List.join([[1], [2, 3], [], [4, 5]]) == [1, 2, 3, 4, 5]
expect List.join([[], []]) == []
expect List.join([]) == []

contains : List a, a -> Bool where a implements Eq

walk : List elem, state, (state, elem -> state) -> state

Description: Build a value by folding over list elements from first to last. Also known as reduce, fold, foldl.

[2, 4, 8] |> List.walk(0, Num.add)  # returns 14

walk_with_index : List elem, state, (state, elem, U64 -> state) -> state

Description: Like [walk], but at each step the function also receives the index of the current element.

walk_with_index_until : List elem, state, (state, elem, U64 -> [ Continue state, Break state ]) -> state

Description: Like [walk_until], but at each step the function also receives the index of the current element.

walk_backwards : List elem, state, (state, elem -> state) -> state

Description: Note that in other languages, walk_backwards is sometimes called reduce_right, fold, fold_right, or foldr.

walk_until : List elem, state, (state, elem -> [ Continue state, Break state ]) -> state

Description: Like [List.walk], but can stop early by returning Break state.

walk_backwards_until : List elem, state, (state, elem -> [ Continue state, Break state ]) -> state

Description: Same as [List.walk_until], but does it from the end of the list instead.

walk_from : List elem, U64, state, (state, elem -> state) -> state

Description: Walks to the end of the list from a specified starting index

walk_from_until : List elem, U64, state, (state, elem -> [ Continue state, Break state ]) -> state

Description: A combination of [List.walk_from] and [List.walk_until]

sum : List (Num a) -> Num a

product : List (Num a) -> Num a

any : List a, (a -> Bool) -> Bool

Description: Run the given predicate on each element of the list, returning Bool.true if any of the elements satisfy it.

all : List a, (a -> Bool) -> Bool

Description: Run the given predicate on each element of the list, returning Bool.true if all of the elements satisfy it.

keep_if : List a, (a -> Bool) -> List a

Description: Returns elements where the predicate returns Bool.true. Mutates in place if list is unique.

List.keep_if([1, 2, 3, 4], (|num| num > 2))  # [3, 4]

keep_if_try! : List a, (a => Result Bool err) => Result (List a) err

Description: Run an effectful function that returns a [Result] on each element of a list, and return all the elements for which the function returned Ok(Bool.true).

dirs_only = List.keep_if_try!(path_list, Path.is_dir!)?

drop_if : List a, (a -> Bool) -> List a

Description: Run the given function on each element of a list, and return all the elements for which the function returned Bool.false.

List.drop_if([1, 2, 3, 4], (|num| num > 2))

Performance Details

List.drop_if has the same performance characteristics as [List.keep_if]. See its documentation for details on those characteristics!

count_if : List a, (a -> Bool) -> U64

Description: Run the given function on each element of a list, and return the number of elements for which the function returned Bool.true.

expect List.count_if([1, -2, -3], Num.is_negative) == 2
expect List.count_if([1, 2, 3], (|num| num > 1)) == 2

keep_oks : List before, (before -> Result after *) -> List after

Description: This works like [List.map], except only the transformed values that are wrapped in Ok are kept. Any that are wrapped in Err are dropped.

expect List.keep_oks(["1", "Two", "23", "Bird"], Str.to_i32) == [1, 23]

expect List.keep_oks([["a", "b"], [], ["c", "d", "e"], [] ], List.first) == ["a", "c"]

fn = |str| if Str.is_empty(str) then Err(StrWasEmpty) else Ok(str)
expect List.keep_oks(["", "a", "bc", "", "d", "ef", ""], fn) == ["a", "bc", "d", "ef"]

keep_errs : List before, (before -> Result * after) -> List after

Description: This works like [List.map], except only the transformed values that are wrapped in Err are kept. Any that are wrapped in Ok are dropped.

List.keep_errs([["a", "b"], [], [], ["c", "d", "e"]], List.last)

fn = |str| if Str.is_empty(str) then Err(StrWasEmpty) else Okd(Str.len(str))

List.keep_errs(["", "a", "bc", "", "d", "ef", ""], fn)

map : List a, (a -> b) -> List b

Description: Convert each element in the list to something new, by calling a conversion function on each of them. Then return a new list of the converted values.

expect List.map([1, 2, 3], (|num| num + 1)) == [2, 3, 4]

expect List.map(["", "a", "bc"], Str.is_empty) == [Bool.true, Bool.false, Bool.false]

map2 : List a, List b, (a, b -> c) -> List c

Description: Run a transformation function on the first element of each list, and use that as the first element in the returned list. Repeat until a list runs out of elements.

Some languages have a function named zip, which does something similar to calling [List.map2] passing two lists and Pair:

zipped = List.map2(["a", "b", "c"], [1, 2, 3], Pair)

map3 : List a, List b, List c, (a, b, c -> d) -> List d

Description: Run a transformation function on the first element of each list, and use that as the first element in the returned list. Repeat until a list runs out of elements.

map4 : List a, List b, List c, List d, (a, b, c, d -> e) -> List e

Description: Run a transformation function on the first element of each list, and use that as the first element in the returned list. Repeat until a list runs out of elements.

map_with_index : List a, (a, U64 -> b) -> List b

Description: This works like [List.map], except it also passes the index of the element to the conversion function.

expect List.map_with_index([10, 20, 30], (|num, index| num + index)) == [10, 21, 32]

Description: Returns a list of all the integers between start and end.

To include the start and end integers themselves, use At like so:

List.range({ start: At 2, end: At 5 }) == [2, 3, 4, 5]

To exclude them, use After and Before, like so:

List.range({ start: After 2, end: Before 5 }) == [3, 4]

You can have the list end at a certain length rather than a certain integer:

List.range({ start: At 6, end: Length 4 }) == [6, 7, 8, 9]

If step is specified, each integer increases by that much. (step: 1 is the default.)

List.range({ start: After 0, end: Before 9, step: 3 }) == [3, 6]

List.range will also generate a reversed list if step is negative or end comes before start:

List.range({ start: At 5, end: At 2 }) == [5, 4, 3, 2]

All of these options are compatible with the others. For example, you can use At or After with start regardless of what end and step are set to.

sort_with : List a, (a, a -> [ LT, EQ, GT ]) -> List a

Description: Sort with a custom comparison function

sort_asc : List (Num a) -> List (Num a)

Description: Sorts a list of numbers in ascending order (lowest to highest).

To sort in descending order (highest to lowest), use [List.sort_desc] instead.

sort_desc : List (Num a) -> List (Num a)

Description: Sorts a list of numbers in descending order (highest to lowest).

To sort in ascending order (lowest to highest), use [List.sort_asc] instead.

swap : List a, U64, U64 -> List a

first : List a -> Result a [ListWasEmpty]

Description: Returns the first element in the list, or ListWasEmpty if it was empty.

take_first : List elem, U64 -> List elem

Description: Returns the given number of elements from the beginning of the list.

List.take_first([1, 2, 3, 4, 5, 6, 7, 8], 4) == [1, 2, 3, 4]

If there are fewer elements in the list than the requested number, returns the entire list.

List.take_first([1, 2], 5) == [1, 2]

To remove elements from the beginning of the list, use List.take_last.

To remove elements from both the beginning and end of the list, use List.sublist.

To split the list into two lists, use List.split_at.

take_last : List elem, U64 -> List elem

Description: Returns the given number of elements from the end of the list.

List.take_last([1, 2, 3, 4, 5, 6, 7, 8], 4) == [5, 6, 7, 8]

If there are fewer elements in the list than the requested number, returns the entire list.

List.take_last([1, 2], 5) == [1, 2]

To remove elements from the end of the list, use List.take_first.

To remove elements from both the beginning and end of the list, use List.sublist.

To split the list into two lists, use List.split_at.

drop_first : List elem, U64 -> List elem

Description: Drops n elements from the beginning of the list.

drop_last : List elem, U64 -> List elem

Description: Drops n elements from the end of the list.

drop_at : List elem, U64 -> List elem

Description: Drops the element at the given index from the list.

This has no effect if the given index is outside the bounds of the list.

To replace the element at a given index, instead of dropping it, see [List.set].

min : List (Num a) -> Result (Num a) [ListWasEmpty]

max : List (Num a) -> Result (Num a) [ListWasEmpty]

join_map : List a, (a -> List b) -> List b

Description: Like [List.map], except the transformation function wraps the return value in a list. At the end, all the lists get joined together into one list.

You may know a similar function named concat_map in other languages.

find_first : List elem, (elem -> Bool) -> Result elem [NotFound]

Description: Returns the first element of the list satisfying a predicate function. If no satisfying element is found, an Err NotFound is returned.

find_last : List elem, (elem -> Bool) -> Result elem [NotFound]

Description: Returns the last element of the list satisfying a predicate function. If no satisfying element is found, an Err NotFound is returned.

find_first_index : List elem, (elem -> Bool) -> Result U64 [NotFound]

Description: Returns the index at which the first element in the list satisfying a predicate function can be found. If no satisfying element is found, an Err NotFound is returned.

find_last_index : List elem, (elem -> Bool) -> Result U64 [NotFound]

Description: Returns the last index at which the first element in the list satisfying a predicate function can be found. If no satisfying element is found, an Err NotFound is returned.

sublist : List elem, { start : U64, len : U64 } -> List elem

Description: Returns a subsection of the given list, beginning at the start index and including a total of len elements.

If start is outside the bounds of the given list, returns the empty list.

List.sublist([1, 2, 3], { start: 4, len: 0 })

If more elements are requested than exist in the list, returns as many as it can.

List.sublist([1, 2, 3, 4, 5], { start: 2, len: 10 })

If you want a sublist which goes all the way to the end of the list, no matter how long the list is, List.take_last can do that more efficiently.

Some languages have a function called slice which works similarly to this.

intersperse : List elem, elem -> List elem

Description: Intersperses sep between the elements of list

List.intersperse([1, 2, 3], 9) == [1, 9, 2, 9, 3]

starts_with : List elem, List elem -> Bool where elem implements Eq

Description: Returns Bool.true if the first list starts with the second list.

If the second list is empty, this always returns Bool.true; every list is considered to "start with" an empty list.

If the first list is empty, this only returns Bool.true if the second list is empty.

ends_with : List elem, List elem -> Bool where elem implements Eq

Description: Returns Bool.true if the first list ends with the second list.

If the second list is empty, this always returns Bool.true; every list is considered to "end with" an empty list.

If the first list is empty, this only returns Bool.true if the second list is empty.

split_at : List elem, U64 -> { before : List elem, others : List elem }

Description: Splits the list into two lists, around the given index.

The returned lists are labeled before and others. The before list will contain all the elements whose index in the original list was less than than the given index, # and the others list will be all the others. (This means if you give an index of 0, the before list will be empty and the others list will have the same elements as the original list.)

split_on : List a, a -> List (List a) where a implements Eq

Description: Splits the input list on the delimiter element.

List.split_on([1, 2, 3], 2) == [[1], [3]]

split_on_list : List a, List a -> List (List a) where a implements Eq

Description: Splits the input list on the delimiter list.

List.split_on_list([1, 2, 3], [1, 2]) == [[], [3]]

split_first : List elem, elem -> Result { before : List elem, after : List elem } [NotFound] where elem implements Eq

Description: Returns the elements before the first occurrence of a delimiter, as well as the remaining elements after that occurrence. If the delimiter is not found, returns Err.

List.split_first([Foo, Z, Bar, Z, Baz], Z) == Ok({ before: [Foo], after: [Bar, Z, Baz] })

split_last : List elem, elem -> Result { before : List elem, after : List elem } [NotFound] where elem implements Eq

Description: Returns the elements before the last occurrence of a delimiter, as well as the remaining elements after that occurrence. If the delimiter is not found, returns Err.

List.split_last([Foo, Z, Bar, Z, Baz], Z) == Ok({ before: [Foo, Z, Bar], after: [Baz] })

chunks_of : List a, U64 -> List (List a)

Description: Splits the list into many chunks, each of which is length of the given chunk size. The last chunk will be shorter if the list does not evenly divide by the chunk size. If the provided list is empty or if the chunk size is 0 then the result is an empty list.

map_try : List elem, (elem -> Result ok err) -> Result (List ok) err

Description: Like [List.map], except the transformation function returns a [Result]. If that function ever returns Err, [map_try] immediately returns that Err. If it returns Ok for every element, [map_try] returns Ok with the transformed list.

map_try! : List elem, (elem => Result ok err) => Result (List ok) err

Description: Like [List.map_try], but with an effectful function.

file_list = ["a.txt", "b.txt", "c.txt"]
file_contents =
    List.map_try!(file_list, |file| File.read_utf8!(file))

walk_try : List elem, state, (state, elem -> Result state err) -> Result state err

Description: Like [List.walk], but stops early and returns Err if the function returns Err.

concat_utf8 : List U8, Str -> List U8

Description: Concatenates the bytes of a string encoded as utf8 to a list of bytes.

expect List.concat_utf8([1, 2, 3, 4], "🐦") == [1, 2, 3, 4, 240, 159, 144, 166]

for_each! : List a, (a => {}) => {}

Description: Run an effectful function for each element on the list.

List.for_each!(["Alice", "Bob", "Charlie"], |name|
    create_account!(name)
    log!("Account created")
)

If the function might fail or you need to return early, use [for_each_try!].

for_each_try! : List a, (a => Result {} err) => Result {} err

Description: Run an effectful function that might fail for each element on the list.

If the function returns Err, the iteration stops and the error is returned.

List.for_each_try!(files_to_delete, |path|
    File.delete!(path)?

    Stdout.line!("${path} deleted")
)

walk! : List elem, state, (state, elem => state) => state

Description: Build a value from the contents of a list, using an effectful function.

now_multiples = List.walk!([1, 2, 3], [], |nums, i|
     now = Utc.now!({}) |> Utc.to_millis_since_epoch
     List.append(nums, now * i)
)

This is the same as [walk], except that the step function can have effects.

walk_try! : List elem, state, (state, elem => Result state err) => Result state err

Description: Build a value from the contents of a list, using an effectful function that might fail.

If the function returns Err, the iteration stops and the error is returned.

names =
    List.walk_try!(
        ["First", "Middle", "Last"],
        [],
        |accumulator, which|
            Stdout.write!("${which} name: ")?
            name = Stdin.line!({})?
            Ok(List.append(accumulator, name)),
    )?

This is the same as [walk_try], except that the step function can have effects.

Dict

Associative array mapping keys to values. Maintains insertion order for [Dict.keys]/[Dict.values], but [Dict.remove] moves last element into removed slot (O(1) removal). Based on IndexMap/unordered_dense.

Dict.empty({}) |> Dict.insert("London", 8_961_989) |> Dict.get("London")  # Ok(8_961_989)

empty : {} -> Dict * *

Description: Return an empty dictionary.

empty_dict = Dict.empty({})

with_capacity : U64 -> Dict * *

Description: Return a dictionary with space allocated for a number of entries. This may provide a performance optimization if you know how many entries will be inserted.

reserve : Dict k v, U64 -> Dict k v

Description: Enlarge the dictionary for at least capacity additional elements

release_excess_capacity : Dict k v -> Dict k v

Description: Shrink the memory footprint of a dictionary such that capacity is as small as possible. This function will require regenerating the metadata if the size changes. There will still be some overhead due to dictionary metadata always being a power of 2.

capacity : Dict * * -> U64

Description: Returns the max number of elements the dictionary can hold before requiring a rehash.

food_dict =
    Dict.empty({})
    |> Dict.insert("apple", "fruit")

capacity_of_dict = Dict.capacity(food_dict)

single : k, v -> Dict k v

Description: Returns a dictionary containing the key and value provided as input.

expect
    Dict.single("A", "B")
    |> Bool.is_eq(Dict.empty({}) |> Dict.insert("A", "B"))

from_list : List ( k, v ) -> Dict k v

Description: Returns dictionary with the keys and values specified by the input [List].

expect
    Dict.single(1, "One")
    |> Dict.insert(2, "Two")
    |> Dict.insert(3, "Three")
    |> Dict.insert(4, "Four")
    |> Bool.is_eq(Dict.from_list([(1, "One"), (2, "Two"), (3, "Three"), (4, "Four")]))

Performance Details

This will build up from an empty dictionary to minimize totally memory use. If the list has few duplicate keys, it would be faster to allocate a dictionary with the same capacity of the list and walk it calling [Dict.insert]

len : Dict * * -> U64

Description: Returns the number of values in the dictionary.

expect
    Dict.empty({})
    |> Dict.insert("One", "A Song")
    |> Dict.insert("Two", "Candy Canes")
    |> Dict.insert("Three", "Boughs of Holly")
    |> Dict.len
    |> Bool.is_eq(3)

is_empty : Dict * * -> Bool

Description: Check if the dictionary is empty.

Dict.is_empty(Dict.empty({}) |> Dict.insert("key", 42))

Dict.is_empty(Dict.empty({}))

clear : Dict k v -> Dict k v

Description: Clears all elements from a dictionary keeping around the allocation if it isn't huge.

songs =
       Dict.empty({})
       |> Dict.insert("One", "A Song")
       |> Dict.insert("Two", "Candy Canes")
       |> Dict.insert("Three", "Boughs of Holly")

clear_songs = Dict.clear(songs)

expect Dict.len(clear_songs) == 0

map : Dict k a, (k, a -> b) -> Dict k b

Description: Convert each value in the dictionary to something new, by calling a conversion function on each of them which receives both the key and the old value. Then return a new dictionary containing the same keys and the converted values.

join_map : Dict a b, (a, b -> Dict x y) -> Dict x y

Description: Like [Dict.map], except the transformation function wraps the return value in a dictionary. At the end, all the dictionaries get joined together (using [Dict.insert_all]) into one dictionary.

You may know a similar function named concat_map in other languages.

walk : Dict k v, state, (state, k, v -> state) -> state

Description: Iterate through the keys and values in the dictionary and call the provided function with signature state, k, v -> state for each value, with an initial state value provided for the first call.

expect
    Dict.empty({})
    |> Dict.insert("Apples", 12)
    |> Dict.insert("Orange", 24)
    |> Dict.walk(0, (\count, _, qty -> count + qty))
    |> Bool.is_eq(36)

walk_until : Dict k v, state, (state, k, v -> [ Continue state, Break state ]) -> state

Description: Like [Dict.walk], but can stop early by returning Break state.

keep_if : Dict k v, ( ( k, v ) -> Bool) -> Dict k v

Description: Run the given function on each key-value pair of a dictionary, and return a dictionary with just the pairs for which the function returned Bool.true.

expect Dict.empty({})
    |> Dict.insert("Alice", 17)
    |> Dict.insert("Bob", 18)
    |> Dict.insert("Charlie", 19)
    |> Dict.keep_if(\(_k, v) -> v >= 18)
    |> Dict.len
    |> Bool.is_eq(2)

drop_if : Dict k v, ( ( k, v ) -> Bool) -> Dict k v

Description: Run the given function on each key-value pair of a dictionary, and return a dictionary with just the pairs for which the function returned Bool.false.

expect Dict.empty({})
    |> Dict.insert("Alice", 17)
    |> Dict.insert("Bob", 18)
    |> Dict.insert("Charlie", 19)
    |> Dict.drop_if(\(_k, v) -> v >= 18)
    |> Dict.len
    |> Bool.is_eq(1)

get : Dict k v, k -> Result v [KeyNotFound]

Description: Get the value for a given key. If there is a value for the specified key it will return [Ok value], otherwise return [Err KeyNotFound].

dictionary =
    Dict.empty({})
    |> Dict.insert(1,s "Apple")
    |> Dict.insert(2,s "Orange")

expect Dict.get(dictionary, 1) == Ok("Apple")
expect Dict.get(dictionary, 2000) == Err(KeyNotFound)

contains : Dict k v, k -> Bool

Description: Check if the dictionary has a value for a specified key.

expect
    Dict.empty({})
    |> Dict.insert(1234, "5678")
    |> Dict.contains(1234)
    |> Bool.is_eq(Bool.true)

insert : Dict k v, k, v -> Dict k v

Description: Insert a value into the dictionary at a specified key.

expect
    Dict.empty({})
    |> Dict.insert("Apples", 12)
    |> Dict.get("Apples")
    |> Bool.is_eq(Ok(12))

remove : Dict k v, k -> Dict k v

Description: Remove a value from the dictionary for a specified key.

expect
    Dict.empty({})
    |> Dict.insert("Some", "Value")
    |> Dict.remove("Some")
    |> Dict.len
    |> Bool.is_eq(0)

update : Dict k v, k, (Result v [Missing] -> Result v [Missing]) -> Dict k v

Description: Insert or remove a value for a specified key. This function enables a performance optimization for the use case of providing a default when a value is missing. This is more efficient than doing both a Dict.get and then a Dict.insert call, and supports being piped.

alter_value : Result Bool [Missing] -> Result Bool [Missing]
alter_value = \possible_value ->
    when possible_value is
        Err Missing -> Ok(Bool.false)
        Ok value -> if value then Err(Missing) else Ok(Bool.true)

expect Dict.update(Dict.empty({}), "a", alter_value) == Dict.single("a", Bool.false)
expect Dict.update(Dict.single("a", Bool.false), "a", alter_value) == Dict.single("a", Bool.true)
expect Dict.update(Dict.single("a", Bool.true), "a", alter_value) == Dict.empty({})

to_list : Dict k v -> List ( k, v )

Description: Returns the keys and values of a dictionary as a [List]. This requires allocating a temporary list, prefer using [Dict.to_list] or [Dict.walk] instead.

expect
    Dict.single(1, "One")
    |> Dict.insert(2, "Two")
    |> Dict.insert(3, "Three")
    |> Dict.insert(4, "Four")
    |> Dict.to_list
    |> Bool.is_eq([(1, "One"), (2, "Two"), (3, "Three"), (4, "Four")])

keys : Dict k v -> List k

Description: Returns the keys of a dictionary as a [List]. This requires allocating a temporary [List], prefer using [Dict.to_list] or [Dict.walk] instead.

expect
    Dict.single(1, "One")
    |> Dict.insert(2, "Two")
    |> Dict.insert(3, "Three")
    |> Dict.insert(4, "Four")
    |> Dict.keys
    |> Bool.is_eq([1,2,3,4])

values : Dict k v -> List v

Description: Returns the values of a dictionary as a [List]. This requires allocating a temporary [List], prefer using [Dict.to_list] or [Dict.walk] instead.

expect
    Dict.single(1, "One")
    |> Dict.insert(2, "Two")
    |> Dict.insert(3, "Three")
    |> Dict.insert(4, "Four")
    |> Dict.values
    |> Bool.is_eq(["One","Two","Three","Four"])

insert_all : Dict k v, Dict k v -> Dict k v

Description: Combine two dictionaries by keeping the union of all the key-value pairs. This means that all the key-value pairs in both dictionaries will be combined. Note that where there are pairs with the same key, the value contained in the second input will be retained, and the value in the first input will be removed.

first =
    Dict.single(1, "Not Me")
    |> Dict.insert(2, "And Me")

second =
    Dict.single(1, "Keep Me")
    |> Dict.insert(3, "Me Too")
    |> Dict.insert(4, "And Also Me")

expected =
    Dict.single(1, "Keep Me")
    |> Dict.insert(2, "And Me")
    |> Dict.insert(3, "Me Too")
    |> Dict.insert(4, "And Also Me")

expect
    Dict.insert_all(first, second) == expected

keep_shared : Dict k v, Dict k v -> Dict k v where v implements Eq

Description: Combine two dictionaries by keeping the intersection of all the key-value pairs. This means that we keep only those pairs that are in both dictionaries. Both the key and value must match to be kept.

first =
    Dict.single(1, "Keep Me")
    |> Dict.insert(2, "And Me")
    |> Dict.insert(3, "Not this one")

second =
    Dict.single(1, "Keep Me")
    |> Dict.insert(2, "And Me")
    |> Dict.insert(3, "This has a different value")
    |> Dict.insert(4, "Or Me")

expected =
    Dict.single(1, "Keep Me")
    |> Dict.insert(2, "And Me")

expect Dict.keep_shared(first, second) == expected

remove_all : Dict k v, Dict k v -> Dict k v

Description: Remove the key-value pairs in the first input that are also in the second using the set difference of the values. This means that we will be left with only those pairs that are in the first dictionary and whose keys are not in the second.

first =
    Dict.single(1, "Keep Me")
    |> Dict.insert(2, "And Me")
    |> Dict.insert(3, "Remove Me")

second =
    Dict.single(3, "Remove Me")
    |> Dict.insert(4, "I do nothing...")

expected =
    Dict.single(1, "Keep Me")
    |> Dict.insert(2, "And Me")

expect Dict.remove_all(first, second) == expected

Set

Description: Provides a set type which stores a collection of unique values, without any ordering

empty : {} -> Set *

Description: Creates a new empty Set.

empty_set = Set.empty({})
count_values = Set.len(empty_set)

expect count_values == 0

with_capacity : U64 -> Set *

Description: Return a set with space allocated for a number of entries. This may provide a performance optimization if you know how many entries will be inserted.

reserve : Set k, U64 -> Set k

Description: Enlarge the set for at least capacity additional elements

release_excess_capacity : Set k -> Set k

Description: Shrink the memory footprint of a set such that capacity is as small as possible. This function will require regenerating the metadata if the size changes. There will still be some overhead due to dictionary metadata always being a power of 2.

single : k -> Set k

Description: Creates a new Set with a single value.

single_item_set = Set.single("Apple")
count_values = Set.len(single_item_set)

expect count_values == 1

insert : Set k, k -> Set k

Description: Insert a value into a Set.

few_item_set =
    Set.empty({})
    |> Set.insert("Apple")
    |> Set.insert("Pear")
    |> Set.insert("Banana")

count_values = Set.len(few_item_set)

expect count_values == 3

len : Set * -> U64

Description: Counts the number of values in a given Set.

few_item_set =
    Set.empty({})
    |> Set.insert("Apple")
    |> Set.insert("Pear")
    |> Set.insert("Banana")

count_values = Set.len(few_item_set)

expect count_values == 3

capacity : Set * -> U64

Description: Returns the max number of elements the set can hold before requiring a rehash.

food_set =
    Set.empty({})
    |> Set.insert("apple")

capacity_of_set = Set.capacity(food_set)

is_empty : Set * -> Bool

Description: Check if the set is empty.

Set.is_empty(Set.empty({}) |> Set.insert(42))

Set.is_empty(Set.empty({}))

remove : Set k, k -> Set k

Description: Removes the value from the given Set.

numbers =
    Set.empty({})
    |> Set.insert(10)
    |> Set.insert(20)
    |> Set.remove(10)

has10 = Set.contains(numbers, 10)
has20 = Set.contains(numbers, 20)

expect has10 == Bool.false
expect has20 == Bool.true

contains : Set k, k -> Bool

Description: Test if a value is in the Set.

Fruit : [Apple, Pear, Banana]

fruit : Set Fruit
fruit =
    Set.single(Apple)
    |> Set.insert(Pear)

has_apple = Set.contains(fruit, Apple)
has_banana = Set.contains(fruit, Banana)

expect has_apple == Bool.true
expect has_banana == Bool.false

to_list : Set k -> List k

Description: Retrieve the values in a Set as a List.

numbers : Set U64
numbers = Set.from_list([1,2,3,4,5])

values = [1,2,3,4,5]

expect Set.to_list(numbers) == values

from_list : List k -> Set k

Description: Create a Set from a List of values.

values =
    Set.empty({})
    |> Set.insert(Banana)
    |> Set.insert(Apple)
    |> Set.insert(Pear)

expect Set.from_list([Pear, Apple, Banana]) == values

union : Set k, Set k -> Set k

Description: Combine two Set collection by keeping the union of all the values pairs. This means that all of the values in both Sets will be combined.

set1 = Set.single(Left)
set2 = Set.single(Right)

expect Set.union(set1, set2) == Set.from_list([Left, Right])

intersection : Set k, Set k -> Set k

Description: Combine two Sets by keeping the intersection of all the values pairs. This means that we keep only those values that are in both Sets.

set1 = Set.from_list([Left, Other])
set2 = Set.from_list([Left, Right])

expect Set.intersection(set1, set2) == Set.single(Left)

difference : Set k, Set k -> Set k

Description: Remove the values in the first Set that are also in the second Set using the set difference of the values. This means that we will be left with only those values that are in the first and not in the second.

first = Set.from_list([Left, Right, Up, Down])
second = Set.from_list([Left, Right])

expect Set.difference(first, second) == Set.from_list([Up, Down])

walk : Set k, state, (state, k -> state) -> state

Description: Iterate through the values of a given Set and build a value.

values = Set.from_list(["March", "April", "May"])

starts_with_letter_m = \month ->
    when Str.to_utf8(month) is
        ['M', ..] -> Bool.true
        _ -> Bool.false

reduce = \state, k ->
    if starts_with_letter_m(k) then
        state + 1
    else
        state

result = Set.walk(values, 0, reduce)

expect result == 2

map : Set a, (a -> b) -> Set b

Description: Convert each value in the set to something new, by calling a conversion function on each of them which receives the old value. Then return a new set containing the converted values.

join_map : Set a, (a -> Set b) -> Set b

Description: Like [Set.map], except the transformation function wraps the return value in a set. At the end, all the sets get joined together (using [Set.union]) into one set.

You may know a similar function named concat_map in other languages.

walk_until : Set k, state, (state, k -> [ Continue state, Break state ]) -> state

Description: Iterate through the values of a given Set and build a value, can stop iterating part way through the collection.

numbers = Set.from_list([1,2,3,4,5,6,42,7,8,9,10])

find42 = \state, k ->
    if k == 42 then
        Break(FoundTheAnswer)
    else
        Continue(state)

result = Set.walk_until(numbers, NotFound, find42)

expect result == FoundTheAnswer

keep_if : Set k, (k -> Bool) -> Set k

Description: Run the given function on each element in the Set, and return a Set with just the elements for which the function returned Bool.true.

expect Set.from_list([1,2,3,4,5])
    |> Set.keep_if(\k -> k >= 3)
    |> Bool.is_eq(Set.from_list([3,4,5]))

drop_if : Set k, (k -> Bool) -> Set k

Description: Run the given function on each element in the Set, and return a Set with just the elements for which the function returned Bool.false.

expect Set.from_list [1,2,3,4,5]
    |> Set.drop_if(\k -> k >= 3)
    |> Bool.is_eq(Set.from_list([1,2]))

Decode

DecodeError : [TooShort]

Description: Error types when decoding a List U8 of utf-8 bytes using a [Decoder]

Description: Return type of a [Decoder].

This can be useful when creating a custom decoder or when using from_bytes_partial. For example writing unit tests, such as;

expect
    input = "\"hello\", " |> Str.to_utf8
    actual = Decode.from_bytes_partial(input, Json.json)
    expected = Ok("hello")

    actual.result == expected

Description: Decodes a List U8 of utf-8 bytes where val is the type of the decoded value, and fmt is a [Decoder] which implements the [DecoderFormatting] ability

Decoding : implements decoder : Decoder val fmt where val implements Decoding, fmt implements DecoderFormatting

Description: Definition of the [Decoding] ability

DecoderFormatting : implements u8 : Decoder U8 fmt where fmt implements DecoderFormatting u16 : Decoder U16 fmt where fmt implements DecoderFormatting u32 : Decoder U32 fmt where fmt implements DecoderFormatting u64 : Decoder U64 fmt where fmt implements DecoderFormatting u128 : Decoder U128 fmt where fmt implements DecoderFormatting i8 : Decoder I8 fmt where fmt implements DecoderFormatting i16 : Decoder I16 fmt where fmt implements DecoderFormatting i32 : Decoder I32 fmt where fmt implements DecoderFormatting i64 : Decoder I64 fmt where fmt implements DecoderFormatting i128 : Decoder I128 fmt where fmt implements DecoderFormatting f32 : Decoder F32 fmt where fmt implements DecoderFormatting f64 : Decoder F64 fmt where fmt implements DecoderFormatting dec : Decoder Dec fmt where fmt implements DecoderFormatting bool : Decoder Bool fmt where fmt implements DecoderFormatting string : Decoder Str fmt where fmt implements DecoderFormatting list : Decoder elem fmt -> Decoder (List elem) fmt where fmt implements DecoderFormatting record : state,
(state, Str -> [ Keep (Decoder state fmt), Skip ]), (state, fmt -> Result val DecodeError) -> Decoder val fmt where fmt implements DecoderFormatting tuple : state,
(state, U64 -> [ Next (Decoder state fmt), TooLong ]), (state -> Result val DecodeError) -> Decoder val fmt where fmt implements DecoderFormatting

Description: Definition of the [DecoderFormatting] ability

custom : (List U8, fmt -> DecodeResult val) -> Decoder val fmt where fmt implements DecoderFormatting

Description: Build a custom [Decoder] function. For example the implementation of decode_bool could be defined as follows;

decode_bool = Decode.custom \bytes, @Json({}) ->
    when bytes is
        ['f', 'a', 'l', 's', 'e', ..] -> { result: Ok(Bool.false), rest: List.drop_first(bytes, 5) }
        ['t', 'r', 'u', 'e', ..] -> { result: Ok Bool.true, rest: List.drop_first(bytes, 4) }
        _ -> { result: Err(TooShort), rest: bytes }

decode_with : List U8, Decoder val fmt, fmt -> DecodeResult val where fmt implements DecoderFormatting

Description: Decode a List U8 utf-8 bytes using a specific [Decoder] function

from_bytes_partial : List U8, fmt -> DecodeResult val where val implements Decoding, fmt implements DecoderFormatting

Description: Decode a List U8 utf-8 bytes and return a DecodeResult

expect
    input = "\"hello\", " |> Str.to_utf8
    actual = Decode.from_bytes_partial(input Json.json)
    expected = Ok("hello")

    actual.result == expected

from_bytes : List U8, fmt -> Result val [Leftover (List U8)]DecodeError where val implements Decoding, fmt implements DecoderFormatting

Description: Decode a List U8 utf-8 bytes and return a [Result] with no leftover bytes expected. If successful returns Ok val, however, if there are bytes remaining returns Err Leftover (List U8).

expect
    input = "\"hello\", " |> Str.to_utf8
    actual = Decode.from_bytes(input, Json.json)
    expected = Ok("hello")

    actual == expected

map_result : DecodeResult a, (a -> b) -> DecodeResult b

Description: Transform the val of a [DecodeResult]

Encode

Encoding : implements to_encoder : val -> Encoder fmt where val implements Encoding, fmt implements EncoderFormatting

EncoderFormatting : implements u8 : U8 -> Encoder fmt where fmt implements EncoderFormatting u16 : U16 -> Encoder fmt where fmt implements EncoderFormatting u32 : U32 -> Encoder fmt where fmt implements EncoderFormatting u64 : U64 -> Encoder fmt where fmt implements EncoderFormatting u128 : U128 -> Encoder fmt where fmt implements EncoderFormatting i8 : I8 -> Encoder fmt where fmt implements EncoderFormatting i16 : I16 -> Encoder fmt where fmt implements EncoderFormatting i32 : I32 -> Encoder fmt where fmt implements EncoderFormatting i64 : I64 -> Encoder fmt where fmt implements EncoderFormatting i128 : I128 -> Encoder fmt where fmt implements EncoderFormatting f32 : F32 -> Encoder fmt where fmt implements EncoderFormatting f64 : F64 -> Encoder fmt where fmt implements EncoderFormatting dec : Dec -> Encoder fmt where fmt implements EncoderFormatting bool : Bool -> Encoder fmt where fmt implements EncoderFormatting string : Str -> Encoder fmt where fmt implements EncoderFormatting list : List elem, (elem -> Encoder fmt) -> Encoder fmt where fmt implements EncoderFormatting record : List { key : Str, value : Encoder fmt } -> Encoder fmt where fmt implements EncoderFormatting tuple : List (Encoder fmt) -> Encoder fmt where fmt implements EncoderFormatting tag : Str, List (Encoder fmt) -> Encoder fmt where fmt implements EncoderFormatting

custom : (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting

Description: Creates a custom encoder from a given function.

expect
    # Appends the byte 42
    custom_encoder = Encode.custom(\bytes, _fmt -> List.append(bytes, 42))

    actual = Encode.append_with([], custom_encoder, Core.json)
    expected = [42] # Expected result is a list with a single byte, 42

    actual == expected

append_with : List U8, Encoder fmt, fmt -> List U8 where fmt implements EncoderFormatting

append : List U8, val, fmt -> List U8 where val implements Encoding, fmt implements EncoderFormatting

Description: Appends the encoded representation of a value to an existing list of bytes.

expect
    actual = Encode.append([], { foo: 43 }, Core.json)
    expected = Str.to_utf8("""{"foo":43}""")

    actual == expected

to_bytes : val, fmt -> List U8 where val implements Encoding, fmt implements EncoderFormatting

Description: Encodes a value to a list of bytes (List U8) according to the specified format.

expect
    foo_rec = { foo: 42 }

    actual = Encode.to_bytes(foo_rec, Core.json)
    expected = Str.to_utf8("""{"foo":42}""")

    actual == expected

Hash

Hash : implements hash : hasher, a -> hasher where a implements Hash, hasher implements Hasher

Description: A value that can be hashed.

Hasher : implements add_bytes : a, List U8 -> a where a implements Hasher add_u8 : a, U8 -> a where a implements Hasher add_u16 : a, U16 -> a where a implements Hasher add_u32 : a, U32 -> a where a implements Hasher add_u64 : a, U64 -> a where a implements Hasher add_u128 : a, U128 -> a where a implements Hasher complete : a -> U64 where a implements Hasher

Description: Describes a hashing algorithm that is fed bytes and produces an integer hash.

The [Hasher] ability describes general-purpose hashers. It only allows emission of 64-bit unsigned integer hashes. It is not suitable for cryptographically-secure hashing.

Description: Adds a string into a [Hasher] by hashing its UTF-8 bytes.

Description: Adds a list of [Hash]able elements to a [Hasher] by hashing each element.

hash_bool : a, Bool -> a where a implements Hasher

Description: Adds a single [Bool] to a hasher.

hash_i8 : a, I8 -> a where a implements Hasher

Description: Adds a single I8 to a hasher.

hash_i16 : a, I16 -> a where a implements Hasher

Description: Adds a single I16 to a hasher.

hash_i32 : a, I32 -> a where a implements Hasher

Description: Adds a single I32 to a hasher.

hash_i64 : a, I64 -> a where a implements Hasher

Description: Adds a single I64 to a hasher.

hash_i128 : a, I128 -> a where a implements Hasher

Description: Adds a single I128 to a hasher.

hash_dec : a, Dec -> a where a implements Hasher

Description: Adds a single [Dec] to a hasher.

Description: Adds a container of [Hash]able elements to a [Hasher] by hashing each element. The container is iterated using the walk method passed in. The order of the elements does not affect the final hash.

Box

box : a -> Box a

Description: Allocates a value on the heap. Boxing is an expensive process as it copies the value from the stack to the heap. This may provide a performance optimization for advanced use cases with large values. A platform may require that some values are boxed.

expect Box.unbox(Box.box("Stack Faster")) == "Stack Faster"

unbox : Box a -> a

Description: Returns a boxed value.

expect Box.unbox(Box.box("Stack Faster") == "Stack Faster"

Inspect

KeyValWalker : collection, state, (state, key, val -> state) -> state

ElemWalker : collection, state, (state, elem -> state) -> state

InspectFormatter : implements init : {} -> f where f implements InspectFormatter tag : Str, List (Inspector f) -> Inspector f where f implements InspectFormatter tuple : List (Inspector f) -> Inspector f where f implements InspectFormatter record : List { key : Str, value : Inspector f } -> Inspector f where f implements InspectFormatter bool : Bool -> Inspector f where f implements InspectFormatter str : Str -> Inspector f where f implements InspectFormatter list : list, ElemWalker state list elem, (elem -> Inspector f) -> Inspector f where f implements InspectFormatter set : set, ElemWalker state set elem, (elem -> Inspector f) -> Inspector f where f implements InspectFormatter dict : dict, KeyValWalker state dict key value, (key -> Inspector f), (value -> Inspector f) -> Inspector f where f implements InspectFormatter opaque : * -> Inspector f where f implements InspectFormatter function : * -> Inspector f where f implements InspectFormatter u8 : U8 -> Inspector f where f implements InspectFormatter i8 : I8 -> Inspector f where f implements InspectFormatter u16 : U16 -> Inspector f where f implements InspectFormatter i16 : I16 -> Inspector f where f implements InspectFormatter u32 : U32 -> Inspector f where f implements InspectFormatter i32 : I32 -> Inspector f where f implements InspectFormatter u64 : U64 -> Inspector f where f implements InspectFormatter i64 : I64 -> Inspector f where f implements InspectFormatter u128 : U128 -> Inspector f where f implements InspectFormatter i128 : I128 -> Inspector f where f implements InspectFormatter f32 : F32 -> Inspector f where f implements InspectFormatter f64 : F64 -> Inspector f where f implements InspectFormatter dec : Dec -> Inspector f where f implements InspectFormatter

custom : (f -> f) -> Inspector f where f implements InspectFormatter

apply : Inspector f, f -> f where f implements InspectFormatter

Inspect : implements to_inspector : val -> Inspector f where val implements Inspect, f implements InspectFormatter

inspect : val -> f where val implements Inspect, f implements InspectFormatter

to_str : val -> Str where val implements Inspect