# LLM Prompt for Documentation ## Documentation ### Str #### Utf8ByteProblem **Type Annotation** ```roc [ InvalidStartByte, UnexpectedEndOfSequence, ExpectedContinuation, OverlongEncoding, CodepointTooLarge, EncodesSurrogateHalf ] ``` #### Utf8Problem **Type Annotation** #### isEmpty **Type Annotation** ```roc Str -> Bool ``` **Description** Returns [Bool.true] if the string is empty, and [Bool.false] otherwise. ```roc expect Str.isEmpty "hi!" == Bool.false expect Str.isEmpty "" == Bool.true ``` #### concat **Type Annotation** ```roc Str, Str -> Str ``` **Description** Concatenates two strings together. ```roc expect Str.concat "ab" "cd" == "abcd" expect Str.concat "hello" "" == "hello" expect Str.concat "" "" == "" ``` #### withCapacity **Type Annotation** ```roc U64 -> Str ``` **Description** Returns a string of the specified capacity without any content. This is a performance optimization tool that's like calling [Str.reserve] on an empty string. It's useful when you plan to build up a string incrementally, for example by calling [Str.concat] on it: ```roc greeting = "Hello and welcome to Roc" subject = "Awesome Programmer" # Evaluates to "Hello and welcome to Roc, Awesome Programmer!" helloWorld = Str.withCapacity 45 |> Str.concat greeting |> Str.concat ", " |> Str.concat subject |> Str.concat "!" ``` In general, if you plan to use [Str.concat] on an empty string, it will be faster to start with [Str.withCapacity] than with `""`. Even if you don't know the exact capacity of the string, giving [withCapacity] a higher value than ends up being necessary can help prevent reallocation and copyingโ€”at the cost of using more memory than is necessary. For more details on how the performance optimization works, see [Str.reserve]. #### reserve **Type Annotation** ```roc Str, U64 -> Str ``` **Description** Increase a string's capacity by at least the given number of additional bytes. This can improve the performance of string concatenation operations like [Str.concat] by allocating extra capacity up front, which can prevent the need for reallocations and copies. Consider the following example which does not use [Str.reserve]: ```roc greeting = "Hello and welcome to Roc" subject = "Awesome Programmer" # Evaluates to "Hello and welcome to Roc, Awesome Programmer!" helloWorld = greeting |> Str.concat ", " |> Str.concat subject |> Str.concat "!" ``` In this example: 1. We start with `greeting`, which has both a length and capacity of 24 (bytes). 2. `|> Str.concat ", "` will see that there isn't enough capacity to add 2 more bytes for the `", "`, so it will create a new heap allocation with enough bytes to hold both. (This probably will be more than 7 bytes, because when [Str] functions reallocate, they apply a multiplier to the exact capacity required. This makes it less likely that future realloctions will be needed. The multiplier amount is not specified, because it may change in future releases of Roc, but it will likely be around 1.5 to 2 times the exact capacity required.) Then it will copy the current bytes (`"Hello"`) into the new allocation, and finally concatenate the `", "` into the new allocation. The old allocation will then be deallocated because it's no longer referenced anywhere in the program. 3. `|> Str.concat subject` will again check if there is enough capacity in the string. If it doesn't find enough capacity once again, it will make a third allocation, copy the existing bytes (`"Hello, "`) into that third allocation, and then deallocate the second allocation because it's already no longer being referenced anywhere else in the program. (It may find enough capacity in this particular case, because the previous [Str.concat] allocated something like 1.5 to 2 times the necessary capacity in order to anticipate future concatenations like this...but if something longer than `"World"` were being concatenated here, it might still require further reallocation and copying.) 4. `|> Str.concat "!\n"` will repeat this process once more. This process can have significant performance costs due to multiple reallocation of new strings, copying between old strings and new strings, and deallocation of immediately obsolete strings. Here's a modified example which uses [Str.reserve] to eliminate the need for all that reallocation, copying, and deallocation. ```roc helloWorld = greeting |> Str.reserve 21 |> Str.concat ", " |> Str.concat subject |> Str.concat "!" ``` In this example: 1. We again start with `greeting`, which has both a length and capacity of 24 bytes. 2. `|> Str.reserve 21` will ensure that there is enough capacity in the string for an additional 21 bytes (to make room for `", "`, `"Awesome Programmer"`, and `"!"`). Since the current capacity is only 24, it will create a new 45-byte (24 + 21) heap allocation and copy the contents of the existing allocation (`greeting`) into it. 3. `|> Str.concat ", "` will concatenate `, ` to the string. No reallocation, copying, or deallocation will be necessary, because the string already has a capacity of 45 btytes, and `greeting` will only use 24 of them. 4. `|> Str.concat subject` will concatenate `subject` (`"Awesome Programmer"`) to the string. Again, no reallocation, copying, or deallocation will be necessary. 5. `|> Str.concat "!\n"` will concatenate `"!\n"` to the string, still without any reallocation, copying, or deallocation. Here, [Str.reserve] prevented multiple reallocations, copies, and deallocations during the [Str.concat] calls. Notice that it did perform a heap allocation before any [Str.concat] calls were made, which means that using [Str.reserve] is not free! You should only use it if you actually expect to make use of the extra capacity. Ideally, you'd be able to predict exactly how many extra bytes of capacity will be needed, but this may not always be knowable. When you don't know exactly how many bytes to reserve, you can often get better performance by choosing a number of bytes that's too high, because a number that's too low could lead to reallocations. There's a limit to this, of course; if you always give it ten times what it turns out to need, that could prevent reallocations but will also waste a lot of memory! If you plan to use [Str.reserve] on an empty string, it's generally better to use [Str.withCapacity] instead. #### joinWith **Type Annotation** ```roc List Str, Str -> Str ``` **Description** Combines a [List] of strings into a single string, with a separator string in between each. ```roc expect Str.joinWith ["one", "two", "three"] ", " == "one, two, three" expect Str.joinWith ["1", "2", "3", "4"] "." == "1.2.3.4" ``` #### splitOn **Type Annotation** ```roc 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]. ```roc expect Str.splitOn "1,2,3" "," == ["1","2","3"] expect Str.splitOn "1,2,3" "" == ["1,2,3"] ``` #### repeat **Type Annotation** ```roc Str, U64 -> Str ``` **Description** Repeats a string the given number of times. ```roc expect Str.repeat "z" 3 == "zzz" expect Str.repeat "na" 8 == "nananananananana" ``` Returns `""` when given `""` for the string or `0` for the count. ```roc expect Str.repeat "" 10 == "" expect Str.repeat "anything" 0 == "" ``` #### toUtf8 **Type Annotation** ```roc Str -> List U8 ``` **Description** Returns a [List] of the string's [U8] UTF-8 [code units](https://unicode.org/glossary/#code_unit). (To split the string into a [List] of smaller [Str] values instead of [U8] values, see [Str.splitOn].) ```roc expect Str.toUtf8 "Roc" == [82, 111, 99] expect Str.toUtf8 "้น" == [233, 185, 143] expect Str.toUtf8 "เฎšเฎฟ" == [224, 174, 154, 224, 174, 191] expect Str.toUtf8 "๐Ÿฆ" == [240, 159, 144, 166] ``` #### fromUtf8 **Type Annotation** ```roc List U8 -> Result Str [BadUtf8 Utf8ByteProblem U64] ``` **Description** Converts a [List] of [U8] UTF-8 [code units](https://unicode.org/glossary/#code_unit) to a string. Returns `Err` if the given bytes are invalid UTF-8, and returns `Ok ""` when given `[]`. ```roc expect Str.fromUtf8 [82, 111, 99] == Ok "Roc" expect Str.fromUtf8 [233, 185, 143] == Ok "้น" expect Str.fromUtf8 [224, 174, 154, 224, 174, 191] == Ok "เฎšเฎฟ" expect Str.fromUtf8 [240, 159, 144, 166] == Ok "๐Ÿฆ" expect Str.fromUtf8 [] == Ok "" expect Str.fromUtf8 [255] |> Result.isErr ``` #### startsWith **Type Annotation** ```roc Str, Str -> Bool ``` **Description** Check if the given [Str] starts with a value. ```roc expect Str.startsWith "ABC" "A" == Bool.true expect Str.startsWith "ABC" "X" == Bool.false ``` #### endsWith **Type Annotation** ```roc Str, Str -> Bool ``` **Description** Check if the given [Str] ends with a value. ```roc expect Str.endsWith "ABC" "C" == Bool.true expect Str.endsWith "ABC" "X" == Bool.false ``` #### trim **Type Annotation** ```roc Str -> Str ``` **Description** Return the [Str] with all whitespace removed from both the beginning as well as the end. ```roc expect Str.trim " Hello \n\n" == "Hello" ``` #### trimStart **Type Annotation** ```roc Str -> Str ``` **Description** Return the [Str] with all whitespace removed from the beginning. ```roc expect Str.trimStart " Hello \n\n" == "Hello \n\n" ``` #### trimEnd **Type Annotation** ```roc Str -> Str ``` **Description** Return the [Str] with all whitespace removed from the end. ```roc expect Str.trimEnd " Hello \n\n" == " Hello" ``` #### toDec **Type Annotation** ```roc Str -> Result Dec [InvalidNumStr] ``` **Description** Encode a [Str] to a [Dec]. A [Dec] value is a 128-bit decimal [fixed-point number](https://en.wikipedia.org/wiki/Fixed-point_arithmetic). ```roc expect Str.toDec "10" == Ok 10dec expect Str.toDec "-0.25" == Ok -0.25dec expect Str.toDec "not a number" == Err InvalidNumStr ``` #### toF64 **Type Annotation** ```roc Str -> Result F64 [InvalidNumStr] ``` **Description** Encode a [Str] to a [F64]. A [F64] value is a 64-bit [floating-point number](https://en.wikipedia.org/wiki/IEEE_754) and can be specified with a `f64` suffix. ```roc expect Str.toF64 "0.10" == Ok 0.10f64 expect Str.toF64 "not a number" == Err InvalidNumStr ``` #### toF32 **Type Annotation** ```roc Str -> Result F32 [InvalidNumStr] ``` **Description** Encode a [Str] to a [F32].A [F32] value is a 32-bit [floating-point number](https://en.wikipedia.org/wiki/IEEE_754) and can be specified with a `f32` suffix. ```roc expect Str.toF32 "0.10" == Ok 0.10f32 expect Str.toF32 "not a number" == Err InvalidNumStr ``` #### toU128 **Type Annotation** ```roc 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. ```roc expect Str.toU128 "1500" == Ok 1500u128 expect Str.toU128 "0.1" == Err InvalidNumStr expect Str.toU128 "-1" == Err InvalidNumStr expect Str.toU128 "not a number" == Err InvalidNumStr ``` #### toI128 **Type Annotation** ```roc 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. ```roc expect Str.toI128 "1500" == Ok 1500i128 expect Str.toI128 "-1" == Ok -1i128 expect Str.toI128 "0.1" == Err InvalidNumStr expect Str.toI128 "not a number" == Err InvalidNumStr ``` #### toU64 **Type Annotation** ```roc 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. ```roc expect Str.toU64 "1500" == Ok 1500u64 expect Str.toU64 "0.1" == Err InvalidNumStr expect Str.toU64 "-1" == Err InvalidNumStr expect Str.toU64 "not a number" == Err InvalidNumStr ``` #### toI64 **Type Annotation** ```roc 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. ```roc expect Str.toI64 "1500" == Ok 1500i64 expect Str.toI64 "-1" == Ok -1i64 expect Str.toI64 "0.1" == Err InvalidNumStr expect Str.toI64 "not a number" == Err InvalidNumStr ``` #### toU32 **Type Annotation** ```roc 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. ```roc expect Str.toU32 "1500" == Ok 1500u32 expect Str.toU32 "0.1" == Err InvalidNumStr expect Str.toU32 "-1" == Err InvalidNumStr expect Str.toU32 "not a number" == Err InvalidNumStr ``` #### toI32 **Type Annotation** ```roc 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. ```roc expect Str.toI32 "1500" == Ok 1500i32 expect Str.toI32 "-1" == Ok -1i32 expect Str.toI32 "0.1" == Err InvalidNumStr expect Str.toI32 "not a number" == Err InvalidNumStr ``` #### toU16 **Type Annotation** ```roc 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. ```roc expect Str.toU16 "1500" == Ok 1500u16 expect Str.toU16 "0.1" == Err InvalidNumStr expect Str.toU16 "-1" == Err InvalidNumStr expect Str.toU16 "not a number" == Err InvalidNumStr ``` #### toI16 **Type Annotation** ```roc 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. ```roc expect Str.toI16 "1500" == Ok 1500i16 expect Str.toI16 "-1" == Ok -1i16 expect Str.toI16 "0.1" == Err InvalidNumStr expect Str.toI16 "not a number" == Err InvalidNumStr ``` #### toU8 **Type Annotation** ```roc 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. ```roc expect Str.toU8 "250" == Ok 250u8 expect Str.toU8 "-0.1" == Err InvalidNumStr expect Str.toU8 "not a number" == Err InvalidNumStr expect Str.toU8 "1500" == Err InvalidNumStr ``` #### toI8 **Type Annotation** ```roc 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. ```roc expect Str.toI8 "-15" == Ok -15i8 expect Str.toI8 "150.00" == Err InvalidNumStr expect Str.toI8 "not a number" == Err InvalidNumStr ``` #### countUtf8Bytes **Type Annotation** ```roc Str -> U64 ``` **Description** Gives the number of bytes in a [Str] value. ```roc expect Str.countUtf8Bytes "Hello World" == 11 ``` #### replaceEach **Type Annotation** ```roc 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. ```roc expect Str.replaceEach "foo/bar/baz" "/" "_" == "foo_bar_baz" expect Str.replaceEach "not here" "/" "_" == "not here" ``` #### replaceFirst **Type Annotation** ```roc 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. ```roc expect Str.replaceFirst "foo/bar/baz" "/" "_" == "foo_bar/baz" expect Str.replaceFirst "no slashes here" "/" "_" == "no slashes here" ``` #### replaceLast **Type Annotation** ```roc 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. ```roc expect Str.replaceLast "foo/bar/baz" "/" "_" == "foo/bar_baz" expect Str.replaceLast "no slashes here" "/" "_" == "no slashes here" ``` #### splitFirst **Type Annotation** ```roc Str, Str -> Result { before : Str, after : Str } [NotFound] ``` **Description** Returns the given [Str] before the first occurrence of a [delimiter](https://www.computerhope.com/jargon/d/delimite.htm), as well as the rest of the string after that occurrence. Returns [Err NotFound] if the delimiter is not found. ```roc expect Str.splitFirst "foo/bar/baz" "/" == Ok { before: "foo", after: "bar/baz" } expect Str.splitFirst "no slashes here" "/" == Err NotFound ``` #### splitLast **Type Annotation** ```roc 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. ```roc expect Str.splitLast "foo/bar/baz" "/" == Ok { before: "foo/bar", after: "baz" } expect Str.splitLast "no slashes here" "/" == Err NotFound ``` #### walkUtf8WithIndex **Type Annotation** ```roc 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. ```roc f : List U8, U8, U64 -> List U8 f = \state, byte, _ -> List.append state byte expect Str.walkUtf8WithIndex "ABC" [] f == [65, 66, 67] ``` #### walkUtf8 **Type Annotation** ```roc 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. ```roc sumOfUtf8Bytes = Str.walkUtf8 "Hello, World!" 0 \total, byte -> total + byte expect sumOfUtf8Bytes == 105 ``` #### releaseExcessCapacity **Type Annotation** ```roc 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. #### withPrefix **Type Annotation** ```roc Str, Str -> Str ``` **Description** Adds a prefix to the given [Str]. ```roc expect Str.withPrefix "Awesome" "Roc" == "RocAwesome" ``` #### contains **Type Annotation** ```roc Str, Str -> Bool ``` **Description** Determines whether or not the first Str contains the second. ```roc expect Str.contains "foobarbaz" "bar" expect !(Str.contains "apple" "orange") expect Str.contains "anything" "" ``` #### dropPrefix **Type Annotation** ```roc 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. ```roc expect Str.dropPrefix "bar" "foo" == "bar" expect Str.dropPrefix "foobar" "foo" == "bar" ``` #### dropSuffix **Type Annotation** ```roc 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. ```roc expect Str.dropSuffix "bar" "foo" == "bar" expect Str.dropSuffix "barfoo" "foo" == "bar" ``` ### Num #### Num **Type Annotation** **Description** Represents a number that could be either an [Int] or a [Frac]. This is useful for functions that can work on either, for example [Num.add], whose type is: ```roc add : Num a, Num a -> Num a ``` The number 1.5 technically has the type `Num (Fraction *)`, so when you pass two of them to [Num.add], the answer you get is `3.0 : Num (Fraction *)`. Similarly, the number 0x1 (that is, the integer 1 in hexadecimal notation) technically has the type `Num (Integer *)`, so when you pass two of them to [Num.add], the answer you get is `2 : Num (Integer *)`. The type [`Frac a`](#Frac) is defined to be an alias for `Num (Fraction a)`, so `3.0 : Num (Fraction *)` is the same value as `3.0 : Frac *`. Similarly, the type [`Int a`](#Int) is defined to be an alias for `Num (Integer a)`, so `2 : Num (Integer *)` is the same value as `2 : Int *`. In this way, the [Num] type makes it possible to have `1 + 0x1` return `2 : Int *` and `1.5 + 1.5` return `3.0 : Frac`. ## Number Literals Number literals without decimal points (like `0`, `4` or `360`) have the type `Num *` at first, but usually end up taking on a more specific type based on how they're used. For example, in `(1 + List.len myList)`, the `1` has the type `Num *` at first, but because `List.len` returns a `U64`, the `1` ends up changing from `Num *` to the more specific `U64`, and the expression as a whole ends up having the type `U64`. Sometimes number literals don't become more specific. For example, the `Num.toStr` function has the type `Num * -> Str`. This means that when calling `Num.toStr (5 + 6)`, the expression `(5 + 6)` still has the type `Num *`. When this happens, `Num *` defaults to being an [I64] - so this addition expression would overflow if either 5 or 6 were replaced with a number big enough to cause addition overflow on an [I64] value. If this default of [I64] is not big enough for your purposes, you can add an `i128` to the end of the number literal, like so: ```roc Num.toStr 5_000_000_000i128 ``` This `i128` suffix specifies that you want this number literal to be an [I128] instead of a `Num *`. All the other numeric types have suffixes just like `i128`; here are some other examples: * `215u8` is a `215` value of type [U8] * `76.4f32` is a `76.4` value of type [F32] * `123.45dec` is a `123.45` value of type [Dec] In practice, these are rarely needed. It's most common to write number literals without any suffix. #### Int **Type Annotation** **Description** A fixed-size integer - that is, a number with no fractional component. Integers come in two flavors: signed and unsigned. Signed integers can be negative ("signed" refers to how they can incorporate a minus sign), whereas unsigned integers cannot be negative. Since integers have a fixed size, the size you choose determines both the range of numbers it can represent, and also how much memory it takes up. [U8] is an an example of an integer. It is an unsigned [Int] that takes up 8 bits (aka 1 byte) in memory. The `U` is for Unsigned and the 8 is for 8 bits. Because it has 8 bits to work with, it can store 256 numbers (2^8), and because it is unsigned, its min value is 0. This means the 256 numbers it can store range from 0 to 255. [I8] is a signed integer that takes up 8 bits. The `I` is for Integer, since integers in mathematics are signed by default. Because it has 8 bits just like [U8], it can store 256 numbers (still 2^8), but because it is signed, the range is different. Its 256 numbers range from -128 to 127. Here are some other examples: * [U16] is like [U8], except it takes up 16 bits in memory. It can store 65,536 numbers (2^16), ranging from 0 to 65,536. * [I16] is like [U16], except it is signed. It can still store the same 65,536 numbers (2^16), ranging from -32,768 to 32,767. This pattern continues up to [U128] and [I128]. ## Performance Details In general, using smaller numeric sizes means your program will use less memory. However, if a mathematical operation results in an answer that is too big or too small to fit in the size available for that answer (which is typically the same size as the inputs), then you'll get an overflow error. As such, minimizing memory usage without causing overflows involves choosing number sizes based on your knowledge of what numbers you expect your program to encounter at runtime. Minimizing memory usage does not imply maximum runtime speed! CPUs are typically fastest at performing integer operations on integers that are the same size as that CPU's native machine word size. That means a 64-bit CPU is typically fastest at executing instructions on [U64] and [I64] values, whereas a 32-bit CPU is typically fastest on [U32] and [I32] values. Putting these factors together, here are some reasonable guidelines for optimizing performance through integer size choice: * Start by deciding if this integer should allow negative numbers, and choose signed or unsigned accordingly. * Next, think about the range of numbers you expect this number to hold. Choose the smallest size you will never expect to overflow, no matter the inputs your program receives. (Validating inputs for size, and presenting the user with an error if they are too big, can help guard against overflow.) * Finally, if a particular numeric calculation is running too slowly, you can try experimenting with other number sizes. This rarely makes a meaningful difference, but some processors can operate on different number sizes at different speeds. All number literals without decimal points are compatible with [Int] values. You can optionally put underscores in your [Int] literals. They have no effect on the number's value, but can make large numbers easier to read. ```roc 1_000_000 ``` Integers come in two flavors: *signed* and *unsigned*. * *Unsigned* integers can never be negative. The lowest value they can hold is zero. * *Signed* integers can be negative. Integers also come in different sizes. Choosing a size depends on your performance needs and the range of numbers you need to represent. At a high level, the general trade-offs are: * Larger integer sizes can represent a wider range of numbers. If you absolutely need to represent numbers in a certain range, make sure to pick an integer size that can hold them! * Smaller integer sizes take up less memory. These savings rarely matter in variables and function arguments, but the sizes of integers that you use in data structures can add up. This can also affect whether those data structures fit in [cache lines](https://en.wikipedia.org/wiki/CPU_cache#Cache_performance), which can be a performance bottleneck. * Certain CPUs work faster on some numeric sizes than others. If the CPU is taking too long to run numeric calculations, you may find a performance improvement by experimenting with numeric sizes that are larger than otherwise necessary. However, in practice, doing this typically degrades overall performance, so be careful to measure properly! Here are the different fixed size integer types: | Range | Type | Size | |--------------------------------------------------------|-------|----------| | ` -128` | [I8] | 1 Byte | | ` 127` | | | |--------------------------------------------------------|-------|----------| | ` 0` | [U8] | 1 Byte | | ` 255` | | | |--------------------------------------------------------|-------|----------| | ` -32_768` | [I16] | 2 Bytes | | ` 32_767` | | | |--------------------------------------------------------|-------|----------| | ` 0` | [U16] | 2 Bytes | | ` 65_535` | | | |--------------------------------------------------------|-------|----------| | ` -2_147_483_648` | [I32] | 4 Bytes | | ` 2_147_483_647` | | | |--------------------------------------------------------|-------|----------| | ` 0` | [U32] | 4 Bytes | | ` (over 4 billion) 4_294_967_295` | | | |--------------------------------------------------------|-------|----------| | ` -9_223_372_036_854_775_808` | [I64] | 8 Bytes | | ` 9_223_372_036_854_775_807` | | | |--------------------------------------------------------|-------|----------| | ` 0` | [U64] | 8 Bytes | | ` (over 18 quintillion) 18_446_744_073_709_551_615` | | | |--------------------------------------------------------|-------|----------| | `-170_141_183_460_469_231_731_687_303_715_884_105_728` | [I128]| 16 Bytes | | ` 170_141_183_460_469_231_731_687_303_715_884_105_727` | | | |--------------------------------------------------------|-------|----------| | ` (over 340 undecillion) 0` | [U128]| 16 Bytes | | ` 340_282_366_920_938_463_463_374_607_431_768_211_455` | | | If any operation would result in an [Int] that is either too big or too small to fit in that range (e.g. calling `Num.maxI32 + 1`), then the operation will *overflow*. When an overflow occurs, the program will crash. As such, it's very important to design your code not to exceed these bounds! If you need to do math outside these bounds, consider using a larger numeric size. #### Frac **Type Annotation** **Description** A fixed-size number with a fractional component. Roc fractions come in two flavors: fixed-point base-10 and floating-point base-2. * [Dec] is a 128-bit [fixed-point](https://en.wikipedia.org/wiki/Fixed-point_arithmetic) base-10 number. It's a great default choice, especially when precision is important - for example when representing currency. With [Dec], `0.1 + 0.2` returns `0.3`. [Dec] has 18 decimal places of precision and a range from `-170_141_183_460_469_231_731.687303715884105728` to `170_141_183_460_469_231_731.687303715884105727`. * [F64] and [F32] are [floating-point](https://en.wikipedia.org/wiki/Floating-point_arithmetic) base-2 numbers. They sacrifice precision for lower memory usage and improved performance on some operations. This makes them a good fit for representing graphical coordinates. With [F64], `0.1 + 0.2` returns `0.30000000000000004`. If you don't specify a type, Roc will default to using [Dec] because it's the least error-prone overall. For example, suppose you write this: ```roc wasItPrecise = 0.1 + 0.2 == 0.3 ``` The value of `wasItPrecise` here will be `Bool.true`, because Roc uses [Dec] by default when there are no types specified. In contrast, suppose we use `f32` or `f64` for one of these numbers: ```roc wasItPrecise = 0.1f64 + 0.2 == 0.3 ``` Here, `wasItPrecise` will be `Bool.false` because the entire calculation will have been done in a base-2 floating point calculation, which causes noticeable precision loss in this case. The floating-point numbers ([F32] and [F64]) also have three values which are not ordinary [finite numbers](https://en.wikipedia.org/wiki/Finite_number). They are: * โˆž ([infinity](https://en.wikipedia.org/wiki/Infinity)) * -โˆž (negative infinity) * *NaN* ([not a number](https://en.wikipedia.org/wiki/NaN)) These values are different from ordinary numbers in that they only occur when a floating-point calculation encounters an error. For example: * Dividing a positive [F64] by `0.0` returns โˆž. * Dividing a negative [F64] by `0.0` returns -โˆž. * Dividing a [F64] of `0.0` by `0.0` returns [*NaN*](Num.isNaN). These rules come from the [IEEE-754](https://en.wikipedia.org/wiki/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. There's no literal syntax for these error values, but you can check to see if you ended up with one of them by using #isNaN, #isFinite, and #isInfinite. Whenever a function in this module could return one of these values, that possibility is noted in the function's documentation. ## Performance Details On typical modern CPUs, performance is similar between [Dec], [F64], and [F32] for addition and subtraction. For example, [F32] and [F64] do addition using a single CPU floating-point addition instruction, which typically takes a few clock cycles to complete. In contrast, [Dec] does addition using a few CPU integer arithmetic instructions, each of which typically takes only one clock cycle to complete. Exact numbers will vary by CPU, but they should be similar overall. [Dec] is significantly slower for multiplication and division. It not only needs to do more arithmetic instructions than [F32] and [F64] do, but also those instructions typically take more clock cycles to complete. With [Num.sqrt] and trigonometry functions like [Num.cos], there is an even bigger performance difference. [F32] and [F64] can do these in a single instruction, whereas [Dec] needs entire custom procedures - which use loops and conditionals. If you need to do performance-critical trigonometry or square roots, either [F64] or [F32] is probably a better choice than the usual default choice of [Dec], despite the precision problems they bring. #### Signed128 **Type Annotation** #### Signed64 **Type Annotation** #### Signed32 **Type Annotation** #### Signed16 **Type Annotation** #### Signed8 **Type Annotation** #### Unsigned128 **Type Annotation** #### Unsigned64 **Type Annotation** #### Unsigned32 **Type Annotation** #### Unsigned16 **Type Annotation** #### Unsigned8 **Type Annotation** #### Integer **Type Annotation** #### I128 **Type Annotation** #### I64 **Type Annotation** #### I32 **Type Annotation** #### I16 **Type Annotation** #### I8 **Type Annotation** **Description** A signed 8-bit integer, ranging from -128 to 127 #### U128 **Type Annotation** #### U64 **Type Annotation** #### U32 **Type Annotation** #### U16 **Type Annotation** #### U8 **Type Annotation** #### Decimal **Type Annotation** #### Binary64 **Type Annotation** #### Binary32 **Type Annotation** #### FloatingPoint **Type Annotation** #### F64 **Type Annotation** **Description** A 64-bit [IEEE 754 binary floating-point number](https://en.wikipedia.org/wiki/IEEE_754). [F64] represents decimal numbers less precisely than [Dec] does, but operations on it can be faster because CPUs have hardware-level support for [F64] but not [Dec]. There are other tradeoffs between the two, such as: * [Dec] has a fixed number of digits it can represent before the decimal point, and a fixed number it can represent after the decimal point. In contrast, [F64]'s decimal point can "float"โ€”which conceptually means if you don't need many digits before the decimal point, you can get more digits of precision afterwards (and vice versa). * [Dec] represents its number internally in [base-10](https://en.wikipedia.org/wiki/Decimal), whereas [F64] uses [base-2](https://en.wikipedia.org/wiki/Binary_number). This can lead to imprecise answers like `0.1 + 0.2` returning `0.3` for [Dec] and `0.30000000000000004` for [F64]. This is not a bug; rather, it's a consequence of [F64]'s base-2 representation. * [Dec] always gives a precise answer (or an error), whereas [F64] can lose precision. For example, increasing a very large [F64] number (using addition, perhaps) can result in the whole number portion being incorrect. `1234567890123456789 + 100` correctly results in a number ending in `889` for `Dec`, but results in a number ending `800` in [F64] due to precision loss. #### F32 **Type Annotation** **Description** A 32-bit [IEEE 754 binary floating-point number](https://en.wikipedia.org/wiki/IEEE_754). This works just like [F64] (see its docs for a comparison with [Dec]) except it's smaller. That in turn means it takes up less memory, but can store smaller numbers (and becomes imprecise more easily than [F64] does). #### Dec **Type Annotation** **Description** A [decimal](https://en.wikipedia.org/wiki/Decimal) number. [Dec] is a more precise way to represent decimal numbers (like currency) than [F32] and [F64] are, because [Dec] is represented in memory as base-10. In contrast, [F64] and [F32] are [base-2](https://en.wikipedia.org/wiki/Binary_number) in memory, which can lead to decimal precision loss even when doing addition and subtraction. For example, when using [F64], `0.1 + 0.2` returns 0.30000000000000004, whereas when using [Dec], `0.1 + 0.2` returns 0.3. Under the hood, a [Dec] is an [I128], and operations on it perform [base-10 fixed-point arithmetic](https://en.wikipedia.org/wiki/Fixed-point_arithmetic) with 18 decimal places of precision. This means a [Dec] can represent whole numbers up to slightly over 170 quintillion, along with 18 decimal places. (To be precise, it can store numbers between `-170_141_183_460_469_231_731.687303715884105728` and `170_141_183_460_469_231_731.687303715884105727`.) Why 18 decimal places? It's the highest number of decimal places where you can still convert any [U64] to a [Dec] without losing information. There are some use cases where [F64] and [F32] can be better choices than [Dec] despite their issues with base-10 numbers. For example, in graphical applications they can be a better choice for representing coordinates because they take up less memory, certain relevant calculations run faster (see performance details, below), and base-10 generally isn't as big a concern when dealing with screen coordinates as it is when dealing with currency. Another scenario where [F64] can be a better choice than [Dec] is when representing extremely small numbers. The smallest positive [F64] that can be represented without precision loss is 2^(โˆ’1074), which is about 5 * 10^(-324). Here is that number next to the smallest [Dec] that can be represented: * Smallest [F64]: 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005 * Smallest [Dec]: 0.000000000000000001 This is because [floating-point](https://en.wikipedia.org/wiki/Floating-point_arithmetic) numbers like [F64] can gain more digits of precision after the `.` when they aren't using as many digits before the `.` - and this applies the most if the digit before `.` is `0`. So whereas [Dec] always has 18 digits after the `.`, the number of digits after the `.` that [F32] can [F64] can represent without precision loss depends on what comes before it. ## Performance Details CPUs have dedicated instructions for many [F32] and [F64] operations, but none for [Dec]. Internally, [Dec] is represented as a 128-bit integer and uses multiple instructions to perform fractional operations. This gives [F32] and [F64] performance advantages for many operations. Here's a comparison of about how long [Dec] takes to perform a given operation compared to [F64], based on benchmarks on an [M1](https://en.wikipedia.org/wiki/Apple_M1) CPU: * [add] 0.6x * [sub] 0.6x * [mul] 15x * [div] 55x * [sin] 3.9x * [cos] 3.6x * [tan] 2.3x * [asin] 1.8x * [acos] 1.7x * [atan] 1.7x Keep in mind that arithmetic instructions are basically [the fastest thing a CPU does](http://norvig.com/21-days.html#answers), so (for example) a network request that takes 10 milliseconds to complete would go on this list as about 10000000x. So these performance differences might be more or less noticeable than the base-10 representation differences depending on the use case. #### e **Type Annotation** ```roc Frac * ``` **Description** Euler's number (e) #### pi **Type Annotation** ```roc Frac * ``` **Description** Archimedes' constant (ฯ€) #### tau **Type Annotation** ```roc Frac * ``` **Description** Circle constant (ฯ„) #### toStr **Type Annotation** ```roc Num * -> Str ``` **Description** Convert a number to a [Str]. ```roc Num.toStr 42 ``` Only [Frac] values will include a decimal point, and they will always include one. ```roc Num.toStr 4.2 Num.toStr 4.0 ``` When this function is given a non-[finite](Num.isFinite) [F64] or [F32] value, the returned string will be `"NaN"`, `"โˆž"`, or `"-โˆž"`. #### intCast **Type Annotation** ```roc Int a -> Int b ``` **Description** Convert an [Int] to a new [Int] of the expected type: ```roc # Casts a U8 to a U16 x : U16 x = Num.intCast 255u8 ``` In the case of downsizing, information is lost: ```roc # returns 0, as the bits were truncated. x : U8 x = Num.intCast 256u16 ``` #### compare **Type Annotation** ```roc Num a, Num a -> [ LT, EQ, GT ] ``` #### isLt **Type Annotation** ```roc Num a, Num a -> Bool ``` **Description** Returns `Bool.true` if the first number is less than the second. `a < b` is shorthand for `Num.isLt a b`. If either argument is [*NaN*](Num.isNaN), returns `Bool.false` no matter what. (*NaN* is [defined to be unordered](https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN).) ```roc 5 |> Num.isLt 6 ``` #### isGt **Type Annotation** ```roc Num a, Num a -> Bool ``` **Description** Returns `Bool.true` if the first number is greater than the second. `a > b` is shorthand for `Num.isGt a b`. If either argument is [*NaN*](Num.isNaN), returns `Bool.false` no matter what. (*NaN* is [defined to be unordered](https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN).) ```roc 6 |> Num.isGt 5 ``` #### isLte **Type Annotation** ```roc 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.isLte a b`. If either argument is [*NaN*](Num.isNaN), returns `Bool.false` no matter what. (*NaN* is [defined to be unordered](https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN).) #### isGte **Type Annotation** ```roc 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.isGte a b`. If either argument is [*NaN*](Num.isNaN), returns `Bool.false` no matter what. (*NaN* is [defined to be unordered](https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN).) #### isApproxEq **Type Annotation** ```roc 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.isApproxEq a b == Num.isApproxEq b a` If either argument is [*NaN*](Num.isNaN), returns `Bool.false` no matter what. (*NaN* is [defined to be unordered](https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN).) #### isZero **Type Annotation** ```roc Num a -> Bool ``` **Description** Returns `Bool.true` if the number is `0`, and `Bool.false` otherwise. #### isEven **Type Annotation** ```roc 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 #### isOdd **Type Annotation** ```roc 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 #### isPositive **Type Annotation** ```roc Num a -> Bool ``` **Description** Positive numbers are greater than `0`. #### isNegative **Type Annotation** ```roc Num a -> Bool ``` **Description** Negative numbers are less than `0`. #### toFrac **Type Annotation** ```roc Num * -> Frac * ``` #### isNaN **Type Annotation** ```roc Frac * -> Bool ``` **Description** Returns `Bool.true` if the [Frac] is not a number as defined by [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754) ```roc Num.isNaN (0 / 0) ``` #### isInfinite **Type Annotation** ```roc Frac * -> Bool ``` **Description** Returns `Bool.true` if the [Frac] is positive or negative infinity as defined by [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754) ```roc Num.isInfinite (1 / 0) Num.isInfinite (-1 / 0) ``` #### isFinite **Type Annotation** ```roc Frac * -> Bool ``` **Description** Returns `Bool.true` if the [Frac] is not an infinity as defined by [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754) ```roc Num.isFinite 42 ``` #### abs **Type Annotation** ```roc 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. ```roc 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.minI64] or [Num.minI32]) 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. #### absDiff **Type Annotation** ```roc Num a, Num a -> Num a ``` **Description** Returns the absolute difference between two numbers. ```roc Num.absDiff 5 3 Num.absDiff -3 5 Num.absDiff 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 **Type Annotation** ```roc Num a -> Num a ``` **Description** Returns a negative number when given a positive one, and vice versa. ```roc 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 `\someNum -> 0 - someNum` 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.minI64] or [Num.minI32]) 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 **Type Annotation** ```roc 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`. ```roc 5 + 7 Num.add 5 7 ``` `Num.add` can be convenient in pipelines. ```roc 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 **Type Annotation** ```roc 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`. ```roc 7 - 5 Num.sub 7 5 ``` `Num.sub` can be convenient in pipelines. ```roc 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 **Type Annotation** ```roc 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`. ```roc 5 * 7 Num.mul 5 7 ``` `Num.mul` can be convenient in pipelines. ```roc 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 **Type Annotation** ```roc Num a, Num a -> Num a ``` **Description** Obtains the smaller between two numbers of the same type. ```roc Num.min 100 0 Num.min 3.0 -3.0 ``` #### max **Type Annotation** ```roc Num a, Num a -> Num a ``` **Description** Obtains the greater between two numbers of the same type. ```roc Num.max 100 0 Num.max 3.0 -3.0 ``` #### sin **Type Annotation** ```roc Frac a -> Frac a ``` #### cos **Type Annotation** ```roc Frac a -> Frac a ``` #### tan **Type Annotation** ```roc Frac a -> Frac a ``` #### asin **Type Annotation** ```roc Frac a -> Frac a ``` #### acos **Type Annotation** ```roc Frac a -> Frac a ``` #### atan **Type Annotation** ```roc Frac a -> Frac a ``` #### sqrt **Type Annotation** ```roc 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*](Num.isNaN). * Passing [*NaN*](Num.isNaN) or -โˆž also returns [*NaN*](Num.isNaN). * Passing โˆž returns โˆž. > These rules come from the [IEEE-754](https://en.wikipedia.org/wiki/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. ```roc Num.sqrt 4.0 Num.sqrt 1.5 Num.sqrt 0.0 Num.sqrt -4.0f64 ``` #### sqrtChecked **Type Annotation** ```roc Frac a -> Result (Frac a) [SqrtOfNegative] ``` #### log **Type Annotation** ```roc Frac a -> Frac a ``` **Description** Natural logarithm #### logChecked **Type Annotation** ```roc Frac a -> Result (Frac a) [LogNeedsPositive] ``` #### div **Type Annotation** ```roc 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](https://en.wikipedia.org/wiki/Division_by_zero). 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*](Num.isNaN). > These rules come from the [IEEE-754](https://en.wikipedia.org/wiki/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 #toDec. ```roc 5.0 / 7.0 Num.div 5 7 ``` `Num.div` can be convenient in pipelines. ```roc Num.pi |> Num.div 2.0 ``` #### divChecked **Type Annotation** ```roc Frac a, Frac a -> Result (Frac a) [DivByZero] ``` #### divCeil **Type Annotation** ```roc Int a, Int a -> Int a ``` #### divCeilChecked **Type Annotation** ```roc Int a, Int a -> Result (Int a) [DivByZero] ``` #### divTrunc **Type Annotation** ```roc Int a, Int a -> Int a ``` **Description** Divides two integers, truncating the result towards zero. `a // b` is shorthand for `Num.divTrunc 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. ```roc 5 // 7 Num.divTrunc 5 7 8 // -3 Num.divTrunc 8 -3 ``` #### divTruncChecked **Type Annotation** ```roc Int a, Int a -> Result (Int a) [DivByZero] ``` #### rem **Type Annotation** ```roc 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`. ```roc 5 % 7 Num.rem 5 7 -8 % -3 Num.rem -8 -3 ``` #### remChecked **Type Annotation** ```roc Int a, Int a -> Result (Int a) [DivByZero] ``` #### isMultipleOf **Type Annotation** ```roc Int a, Int a -> Bool ``` #### bitwiseAnd **Type Annotation** ```roc 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. #### bitwiseXor **Type Annotation** ```roc 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. #### bitwiseOr **Type Annotation** ```roc 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. #### bitwiseNot **Type Annotation** ```roc 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. #### shiftLeftBy **Type Annotation** ```roc 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. ```roc shiftLeftBy 0b0000_0011 2 == 0b0000_1100 0b0000_0101 |> shiftLeftBy 2 == 0b0001_0100 ``` In some languages `shiftLeftBy` is implemented as a binary operator `<<`. #### shiftRightBy **Type Annotation** ```roc Int a, U8 -> Int a ``` **Description** Bitwise arithmetic shift of a number by another The most significant bits are copied from the current. ```roc shiftRightBy 0b0000_1100 2 == 0b0000_0011 0b0001_0100 |> shiftRightBy 2 == 0b0000_0101 0b1001_0000 |> shiftRightBy 2 == 0b1110_0100 ``` In some languages `shiftRightBy` is implemented as a binary operator `>>>`. #### shiftRightZfBy **Type Annotation** ```roc 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. ```roc shiftRightZfBy 0b0010_1000 2 == 0b0000_1010 0b0010_1000 |> shiftRightZfBy 2 == 0b0000_1010 0b1001_0000 |> shiftRightZfBy 2 == 0b0010_0100 ``` In some languages `shiftRightZfBy` is implemented as a binary operator `>>`. #### round **Type Annotation** ```roc Frac * -> Int * ``` **Description** Round off the given fraction to the nearest integer. #### floor **Type Annotation** ```roc Frac * -> Int * ``` #### ceiling **Type Annotation** ```roc Frac * -> Int * ``` #### pow **Type Annotation** ```roc 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.powInt] #### powInt **Type Annotation** ```roc 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](https://en.wikipedia.org/wiki/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. #### countLeadingZeroBits **Type Annotation** ```roc Int a -> U8 ``` **Description** Counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer. ```roc Num.countLeadingZeroBits 0b0001_1100u8 3 Num.countLeadingZeroBits 0b0000_0000u8 8 ``` #### countTrailingZeroBits **Type Annotation** ```roc Int a -> U8 ``` **Description** Counts the number of least-significant (trailing in a big-Endian sense) zeroes in an integer. ```roc Num.countTrailingZeroBits 0b0001_1100u8 2 Num.countTrailingZeroBits 0b0000_0000u8 8 ``` #### countOneBits **Type Annotation** ```roc Int a -> U8 ``` **Description** Counts the number of set bits in an integer. ```roc Num.countOneBits 0b0001_1100u8 3 Num.countOneBits 0b0000_0000u8 0 ``` #### addWrap **Type Annotation** ```roc Int range, Int range -> Int range ``` #### addSaturated **Type Annotation** ```roc 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, `addSaturated x y` will yield 255, the maximum value of a `U8`. #### addChecked **Type Annotation** ```roc 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`. #### subWrap **Type Annotation** ```roc Int range, Int range -> Int range ``` #### subSaturated **Type Annotation** ```roc 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, `subSaturated x y` will yield 0, the minimum value of a `U8`. #### subChecked **Type Annotation** ```roc 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`. #### mulWrap **Type Annotation** ```roc Int range, Int range -> Int range ``` #### mulSaturated **Type Annotation** ```roc 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. #### mulChecked **Type Annotation** ```roc 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`. #### minI8 **Type Annotation** ```roc I8 ``` **Description** Returns the lowest number that can be stored in an [I8] without underflowing its available memory and crashing. For reference, this number is `-128`. Note that the positive version of this number is larger than [Num.maxI8], which means if you call [Num.abs] on [Num.minI8], it will overflow and crash! #### maxI8 **Type Annotation** ```roc I8 ``` **Description** Returns the highest number that can be stored in an [I8] without overflowing its available memory and crashing. For reference, this number is `127`. Note that this is smaller than the positive version of [Num.minI8], which means if you call [Num.abs] on [Num.minI8], it will overflow and crash! #### minU8 **Type Annotation** ```roc U8 ``` **Description** Returns the lowest number that can be stored in a [U8] without underflowing its available memory and crashing. For reference, this number is zero, because [U8] is [unsigned](https://en.wikipedia.org/wiki/Signed_number_representations), and zero is the lowest unsigned number. Unsigned numbers cannot be negative. #### maxU8 **Type Annotation** ```roc U8 ``` **Description** Returns the highest number that can be stored in a [U8] without overflowing its available memory and crashing. For reference, this number is `255`. #### minI16 **Type Annotation** ```roc I16 ``` **Description** Returns the lowest number that can be stored in an [I16] without underflowing its available memory and crashing. For reference, this number is `-32_768`. Note that the positive version of this number is larger than [Num.maxI16], which means if you call [Num.abs] on [Num.minI16], it will overflow and crash! #### maxI16 **Type Annotation** ```roc I16 ``` **Description** Returns the highest number that can be stored in an [I16] without overflowing its available memory and crashing. For reference, this number is `32_767`. Note that this is smaller than the positive version of [Num.minI16], which means if you call [Num.abs] on [Num.minI16], it will overflow and crash! #### minU16 **Type Annotation** ```roc U16 ``` **Description** Returns the lowest number that can be stored in a [U16] without underflowing its available memory and crashing. For reference, this number is zero, because [U16] is [unsigned](https://en.wikipedia.org/wiki/Signed_number_representations), and zero is the lowest unsigned number. Unsigned numbers cannot be negative. #### maxU16 **Type Annotation** ```roc U16 ``` **Description** Returns the highest number that can be stored in a [U16] without overflowing its available memory and crashing. For reference, this number is `65_535`. #### minI32 **Type Annotation** ```roc I32 ``` **Description** Returns the lowest number that can be stored in an [I32] without underflowing its available memory and crashing. For reference, this number is `-2_147_483_648`. Note that the positive version of this number is larger than [Num.maxI32], which means if you call [Num.abs] on [Num.minI32], it will overflow and crash! #### maxI32 **Type Annotation** ```roc I32 ``` **Description** Returns the highest number that can be stored in an [I32] without overflowing its available memory and crashing. For reference, this number is `2_147_483_647`, which is over 2 million. Note that this is smaller than the positive version of [Num.minI32], which means if you call [Num.abs] on [Num.minI32], it will overflow and crash! #### minU32 **Type Annotation** ```roc U32 ``` **Description** Returns the lowest number that can be stored in a [U32] without underflowing its available memory and crashing. For reference, this number is zero, because [U32] is [unsigned](https://en.wikipedia.org/wiki/Signed_number_representations), and zero is the lowest unsigned number. Unsigned numbers cannot be negative. #### maxU32 **Type Annotation** ```roc U32 ``` **Description** Returns the highest number that can be stored in a [U32] without overflowing its available memory and crashing. For reference, this number is `4_294_967_295`. #### minI64 **Type Annotation** ```roc I64 ``` **Description** Returns the lowest number that can be stored in an [I64] without underflowing its available memory and crashing. For reference, this number is `-9_223_372_036_854_775_808`, which is under 9 quintillion. Note that the positive version of this number is larger than [Num.maxI64], which means if you call [Num.abs] on [Num.minI64], it will overflow and crash! #### maxI64 **Type Annotation** ```roc I64 ``` **Description** Returns the highest number that can be stored in an [I64] without overflowing its available memory and crashing. For reference, this number is `9_223_372_036_854_775_807`, which is over 9 quintillion. Note that this is smaller than the positive version of [Num.minI64], which means if you call [Num.abs] on [Num.minI64], it will overflow and crash! #### minU64 **Type Annotation** ```roc U64 ``` **Description** Returns the lowest number that can be stored in a [U64] without underflowing its available memory and crashing. For reference, this number is zero, because [U64] is [unsigned](https://en.wikipedia.org/wiki/Signed_number_representations), and zero is the lowest unsigned number. Unsigned numbers cannot be negative. #### maxU64 **Type Annotation** ```roc U64 ``` **Description** Returns the highest number that can be stored in a [U64] without overflowing its available memory and crashing. For reference, this number is `18_446_744_073_709_551_615`, which is over 18 quintillion. #### minI128 **Type Annotation** ```roc I128 ``` **Description** Returns the lowest number that can be stored in an [I128] without underflowing its available memory and crashing. For reference, this number is `-170_141_183_460_469_231_731_687_303_715_884_105_728`. which is under 170 undecillion. Note that the positive version of this number is larger than [Num.maxI128], which means if you call [Num.abs] on [Num.minI128], it will overflow and crash! #### maxI128 **Type Annotation** ```roc I128 ``` **Description** Returns the highest number that can be stored in an [I128] without overflowing its available memory and crashing. For reference, this number is `170_141_183_460_469_231_731_687_303_715_884_105_727`, which is over 170 undecillion. Note that this is smaller than the positive version of [Num.minI128], which means if you call [Num.abs] on [Num.minI128], it will overflow and crash! #### minU128 **Type Annotation** ```roc U128 ``` **Description** Returns the lowest number that can be stored in a [U128] without underflowing its available memory and crashing. For reference, this number is zero, because [U128] is [unsigned](https://en.wikipedia.org/wiki/Signed_number_representations), and zero is the lowest unsigned number. Unsigned numbers cannot be negative. #### maxU128 **Type Annotation** ```roc U128 ``` **Description** Returns the highest number that can be stored in a [U128] without overflowing its available memory and crashing. For reference, this number is `340_282_366_920_938_463_463_374_607_431_768_211_455`, which is over 340 undecillion. #### minF32 **Type Annotation** ```roc F32 ``` #### maxF32 **Type Annotation** ```roc F32 ``` #### minF64 **Type Annotation** ```roc F64 ``` #### maxF64 **Type Annotation** ```roc F64 ``` #### toI8 **Type Annotation** ```roc 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. #### toI16 **Type Annotation** ```roc Int * -> I16 ``` #### toI32 **Type Annotation** ```roc Int * -> I32 ``` #### toI64 **Type Annotation** ```roc Int * -> I64 ``` #### toI128 **Type Annotation** ```roc Int * -> I128 ``` #### toU8 **Type Annotation** ```roc Int * -> U8 ``` #### toU16 **Type Annotation** ```roc Int * -> U16 ``` #### toU32 **Type Annotation** ```roc Int * -> U32 ``` #### toU64 **Type Annotation** ```roc Int * -> U64 ``` #### toU128 **Type Annotation** ```roc Int * -> U128 ``` #### toF32 **Type Annotation** ```roc 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. #### toF64 **Type Annotation** ```roc 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. #### toI8Checked **Type Annotation** ```roc 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`. #### toI16Checked **Type Annotation** ```roc Int * -> Result I16 [OutOfBounds] ``` #### toI32Checked **Type Annotation** ```roc Int * -> Result I32 [OutOfBounds] ``` #### toI64Checked **Type Annotation** ```roc Int * -> Result I64 [OutOfBounds] ``` #### toI128Checked **Type Annotation** ```roc Int * -> Result I128 [OutOfBounds] ``` #### toU8Checked **Type Annotation** ```roc Int * -> Result U8 [OutOfBounds] ``` #### toU16Checked **Type Annotation** ```roc Int * -> Result U16 [OutOfBounds] ``` #### toU32Checked **Type Annotation** ```roc Int * -> Result U32 [OutOfBounds] ``` #### toU64Checked **Type Annotation** ```roc Int * -> Result U64 [OutOfBounds] ``` #### toU128Checked **Type Annotation** ```roc Int * -> Result U128 [OutOfBounds] ``` #### toF32Checked **Type Annotation** ```roc Num * -> Result F32 [OutOfBounds] ``` #### toF64Checked **Type Annotation** ```roc Num * -> Result F64 [OutOfBounds] ``` #### withoutDecimalPoint **Type Annotation** ```roc 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. #### withDecimalPoint **Type Annotation** ```roc 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. #### f32ToParts **Type Annotation** ```roc F32 -> { sign : Bool, exponent : U8, fraction : U32 } ``` **Description** Splits a [F32] into its components according to IEEE 754 standard. #### f64ToParts **Type Annotation** ```roc F64 -> { sign : Bool, exponent : U16, fraction : U64 } ``` **Description** Splits a [F64] into its components according to IEEE 754 standard. #### f32FromParts **Type Annotation** ```roc { 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. #### f64FromParts **Type Annotation** ```roc { 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. #### nanF32 **Type Annotation** ```roc F32 ``` **Description** The value for not-a-number for a [F32] according to the IEEE 754 standard. #### nanF64 **Type Annotation** ```roc F64 ``` **Description** The value for not-a-number for a [F64] according to the IEEE 754 standard. #### infinityF32 **Type Annotation** ```roc F32 ``` **Description** The value for infinity for a [F32] according to the IEEE 754 standard. #### infinityF64 **Type Annotation** ```roc F64 ``` **Description** The value for infinity for a [F64] according to the IEEE 754 standard. ### Bool #### Eq **Type Annotation** ```roc implements isEq : 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 `isEq a b` is `Bool.true`. Not all types support total equality. For example, [`F32`](../Num#F32) and [`F64`](../Num#F64) can be a `NaN` ([Not a Number](https://en.wikipedia.org/wiki/NaN)), and the [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754) floating point standard specifies that two `NaN`s are not equal. #### Bool **Type Annotation** **Description** Represents the boolean true and false using an opaque type. `Bool` implements the `Eq` ability. #### true **Type Annotation** ```roc Bool ``` **Description** The boolean true value. #### false **Type Annotation** ```roc Bool ``` **Description** The boolean false value. #### and **Type Annotation** ```roc Bool, Bool -> Bool ``` **Description** Returns `Bool.true` when both inputs are `Bool.true`. This is equivalent to the logic [AND](https://en.wikipedia.org/wiki/Logical_conjunction) gate. The infix operator `&&` can also be used as shorthand for `Bool.and`. ```roc expect (Bool.and Bool.true Bool.true) == Bool.true expect (Bool.true && Bool.true) == Bool.true expect (Bool.false && Bool.true) == Bool.false expect (Bool.true && Bool.false) == Bool.false expect (Bool.false && Bool.false) == Bool.false ``` ## Performance Details In Roc the `&&` and `||` work the same way as any other function. However, in some languages `&&` and `||` are special-cased. In these languages the compiler will skip evaluating the expression after the first operator under certain circumstances. For example an expression like `enablePets && likesDogs user` would compile to. ```roc if enablePets then likesDogs user else Bool.false ``` Roc does not do this because conditionals like `if` and `when` have a performance cost. Calling a function can sometimes be faster across the board than doing an `if` to decide whether to skip calling it. #### or **Type Annotation** ```roc Bool, Bool -> Bool ``` **Description** Returns `Bool.true` when either input is a `Bool.true`. This is equivalent to the logic [OR](https://en.wikipedia.org/wiki/Logical_disjunction) gate. The infix operator `||` can also be used as shorthand for `Bool.or`. ```roc expect (Bool.or Bool.false Bool.true) == Bool.true expect (Bool.true || Bool.true) == Bool.true expect (Bool.false || Bool.true) == Bool.true expect (Bool.true || Bool.false) == Bool.true expect (Bool.false || Bool.false) == Bool.false ``` ## Performance Details In Roc the `&&` and `||` work the same way as any other functions. However, in some languages `&&` and `||` are special-cased. Refer to the note in `Bool.and` for more detail. #### not **Type Annotation** ```roc Bool -> Bool ``` **Description** Returns `Bool.false` when given `Bool.true`, and vice versa. This is equivalent to the logic [NOT](https://en.wikipedia.org/wiki/Negation) gate. The operator `!` can also be used as shorthand for `Bool.not`. ```roc expect (Bool.not Bool.false) == Bool.true expect (!Bool.false) == Bool.true ``` #### isNotEq **Type Annotation** ```roc a, a -> Bool where a implements Eq ``` **Description** This will call the function `Bool.isEq` on the inputs, and then `Bool.not` on the result. The is equivalent to the logic [XOR](https://en.wikipedia.org/wiki/Exclusive_or) gate. The infix operator `!=` can also be used as shorthand for `Bool.isNotEq`. **Note** that `isNotEq` does not accept arguments whose types contain functions. ```roc expect (Bool.isNotEq Bool.false Bool.true) == Bool.true expect (Bool.false != Bool.false) == Bool.false expect "Apples" != "Oranges" ``` ### Result #### Result **Type Annotation** ```roc [ 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. #### isOk **Type Annotation** ```roc Result ok err -> Bool ``` **Description** Returns `Bool.true` if the result indicates a success, else returns `Bool.false` ```roc Result.isOk (Ok 5) ``` #### isErr **Type Annotation** ```roc Result ok err -> Bool ``` **Description** Returns `Bool.true` if the result indicates a failure, else returns `Bool.false` ```roc Result.isErr (Err "uh oh") ``` #### withDefault **Type Annotation** ```roc Result ok err, ok -> ok ``` **Description** If the result is `Ok`, returns the value it holds. Otherwise, returns the given default value. ```roc Result.withDefault (Ok 7) 42 Result.withDefault (Err "uh oh") 42 ``` #### map **Type Annotation** ```roc 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 [mapErr] to transform an `Err`. ```roc Result.map (Ok 12) Num.neg Result.map (Err "yipes!") Num.neg ``` Functions like `map` are common in Roc; see for example [List.map], `Set.map`, and `Dict.map`. #### mapErr **Type Annotation** ```roc 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] to transform an `Ok`. ```roc Result.mapErr (Err "yipes!") Str.isEmpty Result.mapErr (Ok 12) Str.isEmpty ``` #### mapBoth **Type Annotation** ```roc 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 **Type Annotation** ```roc Result a err, Result b err, (a, b -> c) -> Result c err ``` **Description** Maps the `Ok` values of two `Result`s to a new value using a given transformation, or returns the first `Err` value encountered. #### try **Type Annotation** ```roc 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. Use `onErr` to transform an `Err`. ```roc Result.try (Ok -1) \num -> if num < 0 then Err "negative!" else Ok -num Result.try (Err "yipes!") \num -> if num < 0 then Err "negative!" else Ok -num ``` #### onErr **Type Annotation** ```roc Result a err, (err -> Result a otherErr) -> Result a otherErr ``` **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 `try` to transform an `Ok`. ```roc Result.onErr (Ok 10) \errorNum -> Str.toU64 errorNum Result.onErr (Err "42") \errorNum -> Str.toU64 errorNum ``` #### onErr! **Type Annotation** ```roc Result a err, (err => Result a otherErr) => Result a otherErr ``` **Description** Like [onErr], but it allows the transformation function to produce effects. ```roc Result.onErr (Err "missing user") \msg -> try Stdout.line! "ERROR: $(msg)" Err msg ``` ### List #### isEmpty **Type Annotation** ```roc List * -> Bool ``` **Description** Check if the list is empty. ```roc List.isEmpty [1, 2, 3] List.isEmpty [] ``` #### get **Type Annotation** ```roc 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 ```roc expect List.get [100, 200, 300] 1 == Ok 200 expect List.get [100, 200, 300] 5 == Err OutOfBounds ``` #### replace **Type Annotation** ```roc List a, U64, a -> { list : List a, value : a } ``` #### set **Type Annotation** ```roc List a, U64, a -> List a ``` **Description** Replaces the element at the given index with a replacement. ```roc 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.dropAt]. #### update **Type Annotation** ```roc List a, U64, (a -> a) -> List a ``` **Description** Updates the element at the given index with the given function. ```roc 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 **Type Annotation** ```roc List a, a -> List a ``` **Description** Add a single element to the end of a list. ```roc List.append [1, 2, 3] 4 [0, 1, 2] |> List.append 3 ``` #### appendIfOk **Type Annotation** ```roc 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. ```roc List.appendIfOk [1, 2, 3] (Ok 4) [0, 1, 2] |> List.appendIfOk (Err 3) ``` #### prepend **Type Annotation** ```roc List a, a -> List a ``` **Description** Add a single element to the beginning of a list. ```roc List.prepend [1, 2, 3] 0 [2, 3, 4] |> List.prepend 1 ``` #### prependIfOk **Type Annotation** ```roc 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. ```roc List.prepend [1, 2, 3] (Ok 0) [2, 3, 4] |> List.prepend (Err 1) ``` #### len **Type Annotation** ```roc List * -> U64 ``` **Description** Returns the length of the list - the number of elements it contains. One [List] can store up to `Num.maxI64` elements on 64-bit targets and `Num.maxI32` 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. #### withCapacity **Type Annotation** ```roc U64 -> List * ``` **Description** Create a list with space for at least capacity elements #### reserve **Type Annotation** ```roc List a, U64 -> List a ``` **Description** Enlarge the list for at least capacity additional elements #### releaseExcessCapacity **Type Annotation** ```roc 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 **Type Annotation** ```roc List a, List a -> List a ``` **Description** Put two lists together. ```roc List.concat [1, 2, 3] [4, 5] [0, 1, 2] |> List.concat [3, 4] ``` #### last **Type Annotation** ```roc List a -> Result a [ListWasEmpty] ``` **Description** Returns the last element in the list, or `ListWasEmpty` if it was empty. ```roc expect List.last [1, 2, 3] == Ok 3 expect List.last [] == Err ListWasEmpty ``` #### single **Type Annotation** ```roc a -> List a ``` **Description** A list with a single element in it. This is useful in pipelines, like so: ```roc websites = Str.concat domain ".com" |> List.single ``` #### repeat **Type Annotation** ```roc a, U64 -> List a ``` **Description** Returns a list with the given length, where every element is the given value. #### reverse **Type Annotation** ```roc List a -> List a ``` **Description** Returns the list with its elements reversed. ```roc expect List.reverse [1, 2, 3] == [3, 2, 1] ``` #### join **Type Annotation** ```roc List (List a) -> List a ``` **Description** Join the given lists together into one list. ```roc expect List.join [[1], [2, 3], [], [4, 5]] == [1, 2, 3, 4, 5] expect List.join [[], []] == [] expect List.join [] == [] ``` #### contains **Type Annotation** ```roc List a, a -> Bool where a implements Eq ``` #### walk **Type Annotation** ```roc List elem, state, (state, elem -> state) -> state ``` **Description** Build a value using each element in the list. Starting with a given `state` value, this walks through each element in the list from first to last, running a given `step` function on that element which updates the `state`. It returns the final `state` at the end. You can use it in a pipeline: ```roc [2, 4, 8] |> List.walk 0 Num.add ``` This returns 14 because: * `state` starts at 0 * Each `step` runs `Num.add state elem`, and the return value becomes the new `state`. Here is a table of how `state` changes as [List.walk] walks over the elements `[2, 4, 8]` using [Num.add] as its `step` function to determine the next `state`. state | elem | Num.add state elem :---: | :---: | :----------------: 0 | | 0 | 2 | 2 2 | 4 | 6 6 | 8 | 14 The following returns -6: ```roc [1, 2, 3] |> List.walk 0 Num.sub ``` Note that in other languages, `walk` is sometimes called `reduce`, `fold`, `foldLeft`, or `foldl`. #### walkWithIndex **Type Annotation** ```roc 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. #### walkWithIndexUntil **Type Annotation** ```roc List elem, state, (state, elem, U64 -> [ Continue state, Break state ]) -> state ``` **Description** Like [walkUntil], but at each step the function also receives the index of the current element. #### walkBackwards **Type Annotation** ```roc List elem, state, (state, elem -> state) -> state ``` **Description** Note that in other languages, `walkBackwards` is sometimes called `reduceRight`, `fold`, `foldRight`, or `foldr`. #### walkUntil **Type Annotation** ```roc List elem, state, (state, elem -> [ Continue state, Break state ]) -> state ``` **Description** Same as [List.walk], except you can stop walking early. ## Performance Details Compared to [List.walk], this can potentially visit fewer elements (which can improve performance) at the cost of making each step take longer. However, the added cost to each step is extremely small, and can easily be outweighed if it results in skipping even a small number of elements. As such, it is typically better for performance to use this over [List.walk] if returning `Break` earlier than the last element is expected to be common. #### walkBackwardsUntil **Type Annotation** ```roc List elem, state, (state, elem -> [ Continue state, Break state ]) -> state ``` **Description** Same as [List.walkUntil], but does it from the end of the list instead. #### walkFrom **Type Annotation** ```roc List elem, U64, state, (state, elem -> state) -> state ``` **Description** Walks to the end of the list from a specified starting index #### walkFromUntil **Type Annotation** ```roc List elem, U64, state, (state, elem -> [ Continue state, Break state ]) -> state ``` **Description** A combination of [List.walkFrom] and [List.walkUntil] #### sum **Type Annotation** ```roc List (Num a) -> Num a ``` #### product **Type Annotation** ```roc List (Num a) -> Num a ``` #### any **Type Annotation** ```roc 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 **Type Annotation** ```roc 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. #### keepIf **Type Annotation** ```roc 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.true`. ```roc List.keepIf [1, 2, 3, 4] (\num -> num > 2) ``` ## Performance Details [List.keepIf] always returns a list that takes up exactly the same amount of memory as the original, even if its length decreases. This is because it can't know in advance exactly how much space it will need, and if it guesses a length that's too low, it would have to re-allocate. (If you want to do an operation like this which reduces the memory footprint of the resulting list, you can do two passes over the list with [List.walk] - one to calculate the precise new size, and another to populate the new list.) If given a unique list, [List.keepIf] will mutate it in place to assemble the appropriate list. If that happens, this function will not allocate any new memory on the heap. If all elements in the list end up being kept, Roc will return the original list unaltered. #### dropIf **Type Annotation** ```roc 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`. ```roc List.dropIf [1, 2, 3, 4] (\num -> num > 2) ``` ## Performance Details `List.dropIf` has the same performance characteristics as [List.keepIf]. See its documentation for details on those characteristics! #### countIf **Type Annotation** ```roc 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`. ```roc expect List.countIf [1, -2, -3] Num.isNegative == 2 expect List.countIf [1, 2, 3] (\num -> num > 1 ) == 2 ``` #### keepOks **Type Annotation** ```roc 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. ```roc expect List.keepOks ["1", "Two", "23", "Bird"] Str.toI32 == [1, 23] expect List.keepOks [["a", "b"], [], ["c", "d", "e"], [] ] List.first == ["a", "c"] fn = \str -> if Str.isEmpty str then Err StrWasEmpty else Ok str expect List.keepOks ["", "a", "bc", "", "d", "ef", ""] fn == ["a", "bc", "d", "ef"] ``` #### keepErrs **Type Annotation** ```roc 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. ```roc List.keepErrs [["a", "b"], [], [], ["c", "d", "e"]] List.last fn = \str -> if Str.isEmpty str then Err StrWasEmpty else Ok (Str.len str) List.keepErrs ["", "a", "bc", "", "d", "ef", ""] ``` #### map **Type Annotation** ```roc 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. ```roc expect List.map [1, 2, 3] (\num -> num + 1) == [2, 3, 4] expect List.map ["", "a", "bc"] Str.isEmpty == [Bool.true, Bool.false, Bool.false] ``` #### map2 **Type Annotation** ```roc 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`: ```roc zipped = List.map2 ["a", "b", "c"] [1, 2, 3] Pair ``` #### map3 **Type Annotation** ```roc 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 **Type Annotation** ```roc 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. #### mapWithIndex **Type Annotation** ```roc 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. ```roc expect List.mapWithIndex [10, 20, 30] (\num, index -> num + index) == [10, 21, 32] ``` #### range **Type Annotation** **Description** Returns a list of all the integers between `start` and `end`. To include the `start` and `end` integers themselves, use `At` like so: ```roc List.range { start: At 2, end: At 5 } # returns [2, 3, 4, 5] ``` To exclude them, use `After` and `Before`, like so: ```roc List.range { start: After 2, end: Before 5 } # returns [3, 4] ``` You can have the list end at a certain length rather than a certain integer: ```roc List.range { start: At 6, end: Length 4 } # returns [6, 7, 8, 9] ``` If `step` is specified, each integer increases by that much. (`step: 1` is the default.) ```roc List.range { start: After 0, end: Before 9, step: 3 } # returns [3, 6] ``` List.range will also generate a reversed list if step is negative or end comes before start: ```roc List.range { start: At 5, end: At 2 } # returns [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. #### sortWith **Type Annotation** ```roc List a, (a, a -> [ LT, EQ, GT ]) -> List a ``` **Description** Sort with a custom comparison function #### sortAsc **Type Annotation** ```roc 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.sortDesc] instead. #### sortDesc **Type Annotation** ```roc 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.sortAsc] instead. #### swap **Type Annotation** ```roc List a, U64, U64 -> List a ``` #### first **Type Annotation** ```roc List a -> Result a [ListWasEmpty] ``` **Description** Returns the first element in the list, or `ListWasEmpty` if it was empty. #### takeFirst **Type Annotation** ```roc List elem, U64 -> List elem ``` **Description** Returns the given number of elements from the beginning of the list. ```roc List.takeFirst [1, 2, 3, 4, 5, 6, 7, 8] 4 ``` If there are fewer elements in the list than the requested number, returns the entire list. ```roc List.takeFirst [1, 2] 5 ``` To *remove* elements from the beginning of the list, use `List.takeLast`. To remove elements from both the beginning and end of the list, use `List.sublist`. To split the list into two lists, use `List.splitAt`. #### takeLast **Type Annotation** ```roc List elem, U64 -> List elem ``` **Description** Returns the given number of elements from the end of the list. ```roc List.takeLast [1, 2, 3, 4, 5, 6, 7, 8] 4 ``` If there are fewer elements in the list than the requested number, returns the entire list. ```roc List.takeLast [1, 2] 5 ``` To *remove* elements from the end of the list, use `List.takeFirst`. To remove elements from both the beginning and end of the list, use `List.sublist`. To split the list into two lists, use `List.splitAt`. #### dropFirst **Type Annotation** ```roc List elem, U64 -> List elem ``` **Description** Drops n elements from the beginning of the list. #### dropLast **Type Annotation** ```roc List elem, U64 -> List elem ``` **Description** Drops n elements from the end of the list. #### dropAt **Type Annotation** ```roc 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 **Type Annotation** ```roc List (Num a) -> Result (Num a) [ListWasEmpty] ``` #### max **Type Annotation** ```roc List (Num a) -> Result (Num a) [ListWasEmpty] ``` #### joinMap **Type Annotation** ```roc 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 `concatMap` in other languages. #### findFirst **Type Annotation** ```roc 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. #### findLast **Type Annotation** ```roc 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. #### findFirstIndex **Type Annotation** ```roc 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. #### findLastIndex **Type Annotation** ```roc 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 **Type Annotation** ```roc 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. ```roc 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. ```roc 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.takeLast` can do that more efficiently. Some languages have a function called **`slice`** which works similarly to this. #### intersperse **Type Annotation** ```roc List elem, elem -> List elem ``` **Description** Intersperses `sep` between the elements of `list` ```roc List.intersperse [1, 2, 3] 9 # [1, 9, 2, 9, 3] ``` #### startsWith **Type Annotation** ```roc 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. #### endsWith **Type Annotation** ```roc 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. #### splitAt **Type Annotation** ```roc 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.) #### splitOn **Type Annotation** ```roc List a, a -> List (List a) where a implements Eq ``` **Description** Splits the input list on the delimiter element. ```roc List.splitOn [1, 2, 3] 2 == [[1], [3]] ``` #### splitOnList **Type Annotation** ```roc List a, List a -> List (List a) where a implements Eq ``` **Description** Splits the input list on the delimiter list. ```roc List.splitOnList [1, 2, 3] [1, 2] == [[], [3]] ``` #### splitFirst **Type Annotation** ```roc 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`. ```roc List.splitFirst [Foo, Z, Bar, Z, Baz] Z == Ok { before: [Foo], after: [Bar, Z, Baz] } ``` #### splitLast **Type Annotation** ```roc 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`. ```roc List.splitLast [Foo, Z, Bar, Z, Baz] Z == Ok { before: [Foo, Z, Bar], after: [Baz] } ``` #### chunksOf **Type Annotation** ```roc 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. #### mapTry **Type Annotation** ```roc 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`, [mapTry] immediately returns that `Err`. If it returns `Ok` for every element, [mapTry] returns `Ok` with the transformed list. #### walkTry **Type Annotation** ```roc List elem, state, (state, elem -> Result state err) -> Result state err ``` **Description** Same as [List.walk], except you can stop walking early by returning `Err`. ## Performance Details Compared to [List.walk], this can potentially visit fewer elements (which can improve performance) at the cost of making each step take longer. However, the added cost to each step is extremely small, and can easily be outweighed if it results in skipping even a small number of elements. As such, it is typically better for performance to use this over [List.walk] if returning `Break` earlier than the last element is expected to be common. #### concatUtf8 **Type Annotation** ```roc List U8, Str -> List U8 ``` **Description** Concatenates the bytes of a string encoded as utf8 to a list of bytes. ```roc expect (List.concatUtf8 [1, 2, 3, 4] "๐Ÿฆ") == [1, 2, 3, 4, 240, 159, 144, 166] ``` #### forEach! **Type Annotation** ```roc List a, (a => {}) => {} ``` **Description** Run an effectful function for each element on the list. ```roc List.forEach! ["Alice", "Bob", "Charlie"] \name -> createAccount! name log! "Account created" ``` If the function might fail or you need to return early, use [forEachTry!]. #### forEachTry! **Type Annotation** ```roc 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. ```roc List.forEachTry! filesToDelete \path -> try File.delete! path Stdout.line! "$(path) deleted" ``` ### Dict #### Dict **Type Annotation** **Description** A [dictionary](https://en.wikipedia.org/wiki/Associative_array) that lets you associate keys with values. ## Inserting The most basic way to use a dictionary is to start with an empty one and then: 1. Call [Dict.insert] passing a key and a value, to associate that key with that value in the dictionary. 2. Later, call [Dict.get] passing the same key as before, and it will return the value you stored. Here's an example of a dictionary which uses a city's name as the key, and its population as the associated value. ```roc populationByCity = Dict.empty {} |> Dict.insert "London" 8_961_989 |> Dict.insert "Philadelphia" 1_603_797 |> Dict.insert "Shanghai" 24_870_895 |> Dict.insert "Delhi" 16_787_941 |> Dict.insert "Amsterdam" 872_680 ``` ## Accessing keys or values We can use [Dict.keys] and [Dict.values] functions to get only the keys or only the values. You may notice that these lists have the same order as the original insertion order. This will be true if all you ever do is [Dict.insert] and [Dict.get] operations on the dictionary, but [Dict.remove] operations can change this order. ## Removing We can remove an element from the dictionary, like so: ```roc populationByCity |> Dict.remove "Philadelphia" |> Dict.keys == ["London", "Amsterdam", "Shanghai", "Delhi"] ``` Notice that the order has changed. Philadelphia was not only removed from the list, but Amsterdam - the last entry we inserted - has been moved into the spot where Philadelphia was previously. This is exactly what [Dict.remove] does. It removes an element and moves the most recent insertion into the vacated spot. This move is done as a performance optimization, and it lets [remove] have [constant time complexity](https://en.wikipedia.org/wiki/Time_complexity#Constant_time). Dict is inspired by [IndexMap](https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap.html). The internal implementation of a dictionary is almost identical to [ankerl::unordered_dense](https://github.com/martinus/unordered_dense). It has a list of keys value pairs that is ordered based on insertion. It uses a list of indices into the data as the backing of a hash map. #### empty **Type Annotation** ```roc {} -> Dict * * ``` **Description** Return an empty dictionary. ```roc emptyDict = Dict.empty {} ``` #### withCapacity **Type Annotation** ```roc 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 **Type Annotation** ```roc Dict k v, U64 -> Dict k v ``` **Description** Enlarge the dictionary for at least capacity additional elements #### releaseExcessCapacity **Type Annotation** ```roc 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 **Type Annotation** ```roc Dict * * -> U64 ``` **Description** Returns the max number of elements the dictionary can hold before requiring a rehash. ```roc foodDict = Dict.empty {} |> Dict.insert "apple" "fruit" capacityOfDict = Dict.capacity foodDict ``` #### single **Type Annotation** ```roc k, v -> Dict k v ``` **Description** Returns a dictionary containing the key and value provided as input. ```roc expect Dict.single "A" "B" |> Bool.isEq (Dict.insert (Dict.empty {}) "A" "B") ``` #### fromList **Type Annotation** ```roc List ( k, v ) -> Dict k v ``` **Description** Returns dictionary with the keys and values specified by the input [List]. ```roc expect Dict.single 1 "One" |> Dict.insert 2 "Two" |> Dict.insert 3 "Three" |> Dict.insert 4 "Four" |> Bool.isEq (Dict.fromList [(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 **Type Annotation** ```roc Dict * * -> U64 ``` **Description** Returns the number of values in the dictionary. ```roc expect Dict.empty {} |> Dict.insert "One" "A Song" |> Dict.insert "Two" "Candy Canes" |> Dict.insert "Three" "Boughs of Holly" |> Dict.len |> Bool.isEq 3 ``` #### isEmpty **Type Annotation** ```roc Dict * * -> Bool ``` **Description** Check if the dictionary is empty. ```roc Dict.isEmpty (Dict.empty {} |> Dict.insert "key" 42) Dict.isEmpty (Dict.empty {}) ``` #### clear **Type Annotation** ```roc Dict k v -> Dict k v ``` **Description** Clears all elements from a dictionary keeping around the allocation if it isn't huge. ```roc songs = Dict.empty {} |> Dict.insert "One" "A Song" |> Dict.insert "Two" "Candy Canes" |> Dict.insert "Three" "Boughs of Holly" clearSongs = Dict.clear songs expect Dict.len clearSongs == 0 ``` #### map **Type Annotation** ```roc 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. #### joinMap **Type Annotation** ```roc 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.insertAll]) into one dictionary. You may know a similar function named `concatMap` in other languages. #### walk **Type Annotation** ```roc 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. ```roc expect Dict.empty {} |> Dict.insert "Apples" 12 |> Dict.insert "Orange" 24 |> Dict.walk 0 (\count, _, qty -> count + qty) |> Bool.isEq 36 ``` #### walkUntil **Type Annotation** ```roc Dict k v, state, (state, k, v -> [ Continue state, Break state ]) -> state ``` **Description** Same as [Dict.walk], except you can stop walking early. ## Performance Details Compared to [Dict.walk], this can potentially visit fewer elements (which can improve performance) at the cost of making each step take longer. However, the added cost to each step is extremely small, and can easily be outweighed if it results in skipping even a small number of elements. As such, it is typically better for performance to use this over [Dict.walk] if returning `Break` earlier than the last element is expected to be common. ```roc people = Dict.empty {} |> Dict.insert "Alice" 17 |> Dict.insert "Bob" 18 |> Dict.insert "Charlie" 19 isAdult = \_, _, age -> if age >= 18 then Break Bool.true else Continue Bool.false someoneIsAnAdult = Dict.walkUntil people Bool.false isAdult expect someoneIsAnAdult == Bool.true ``` #### keepIf **Type Annotation** ```roc 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`. ```roc expect Dict.empty {} |> Dict.insert "Alice" 17 |> Dict.insert "Bob" 18 |> Dict.insert "Charlie" 19 |> Dict.keepIf \(_k, v) -> v >= 18 |> Dict.len |> Bool.isEq 2 ``` #### dropIf **Type Annotation** ```roc 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`. ```roc expect Dict.empty {} |> Dict.insert "Alice" 17 |> Dict.insert "Bob" 18 |> Dict.insert "Charlie" 19 |> Dict.dropIf \(_k, v) -> v >= 18 |> Dict.len |> Bool.isEq 1 ``` #### get **Type Annotation** ```roc 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]. ```roc dictionary = Dict.empty {} |> Dict.insert 1 "Apple" |> Dict.insert 2 "Orange" expect Dict.get dictionary 1 == Ok "Apple" expect Dict.get dictionary 2000 == Err KeyNotFound ``` #### contains **Type Annotation** ```roc Dict k v, k -> Bool ``` **Description** Check if the dictionary has a value for a specified key. ```roc expect Dict.empty {} |> Dict.insert 1234 "5678" |> Dict.contains 1234 |> Bool.isEq Bool.true ``` #### insert **Type Annotation** ```roc Dict k v, k, v -> Dict k v ``` **Description** Insert a value into the dictionary at a specified key. ```roc expect Dict.empty {} |> Dict.insert "Apples" 12 |> Dict.get "Apples" |> Bool.isEq (Ok 12) ``` #### remove **Type Annotation** ```roc Dict k v, k -> Dict k v ``` **Description** Remove a value from the dictionary for a specified key. ```roc expect Dict.empty {} |> Dict.insert "Some" "Value" |> Dict.remove "Some" |> Dict.len |> Bool.isEq 0 ``` #### update **Type Annotation** ```roc 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. ```roc alterValue : Result Bool [Missing] -> Result Bool [Missing] alterValue = \possibleValue -> when possibleValue is Err Missing -> Ok Bool.false Ok value -> if value then Err Missing else Ok Bool.true expect Dict.update (Dict.empty {}) "a" alterValue == Dict.single "a" Bool.false expect Dict.update (Dict.single "a" Bool.false) "a" alterValue == Dict.single "a" Bool.true expect Dict.update (Dict.single "a" Bool.true) "a" alterValue == Dict.empty {} ``` #### toList **Type Annotation** ```roc 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.toList] or [Dict.walk] instead. ```roc expect Dict.single 1 "One" |> Dict.insert 2 "Two" |> Dict.insert 3 "Three" |> Dict.insert 4 "Four" |> Dict.toList |> Bool.isEq [(1, "One"), (2, "Two"), (3, "Three"), (4, "Four")] ``` #### keys **Type Annotation** ```roc Dict k v -> List k ``` **Description** Returns the keys of a dictionary as a [List]. This requires allocating a temporary [List], prefer using [Dict.toList] or [Dict.walk] instead. ```roc expect Dict.single 1 "One" |> Dict.insert 2 "Two" |> Dict.insert 3 "Three" |> Dict.insert 4 "Four" |> Dict.keys |> Bool.isEq [1,2,3,4] ``` #### values **Type Annotation** ```roc Dict k v -> List v ``` **Description** Returns the values of a dictionary as a [List]. This requires allocating a temporary [List], prefer using [Dict.toList] or [Dict.walk] instead. ```roc expect Dict.single 1 "One" |> Dict.insert 2 "Two" |> Dict.insert 3 "Three" |> Dict.insert 4 "Four" |> Dict.values |> Bool.isEq ["One","Two","Three","Four"] ``` #### insertAll **Type Annotation** ```roc Dict k v, Dict k v -> Dict k v ``` **Description** Combine two dictionaries by keeping the [union](https://en.wikipedia.org/wiki/Union_(set_theory)) 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. ```roc 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.insertAll first second == expected ``` #### keepShared **Type Annotation** ```roc Dict k v, Dict k v -> Dict k v where v implements Eq ``` **Description** Combine two dictionaries by keeping the [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory)) 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. ```roc 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.keepShared first second == expected ``` #### removeAll **Type Annotation** ```roc 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](https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement) 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. ```roc 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.removeAll first second == expected ``` ### Set #### Set **Type Annotation** **Description** Provides a [set](https://en.wikipedia.org/wiki/Set_(abstract_data_type)) type which stores a collection of unique values, without any ordering #### empty **Type Annotation** ```roc {} -> Set * ``` **Description** Creates a new empty `Set`. ```roc emptySet = Set.empty {} countValues = Set.len emptySet expect countValues == 0 ``` #### withCapacity **Type Annotation** ```roc 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 **Type Annotation** ```roc Set k, U64 -> Set k ``` **Description** Enlarge the set for at least capacity additional elements #### releaseExcessCapacity **Type Annotation** ```roc 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 **Type Annotation** ```roc k -> Set k ``` **Description** Creates a new `Set` with a single value. ```roc singleItemSet = Set.single "Apple" countValues = Set.len singleItemSet expect countValues == 1 ``` #### insert **Type Annotation** ```roc Set k, k -> Set k ``` **Description** Insert a value into a `Set`. ```roc fewItemSet = Set.empty {} |> Set.insert "Apple" |> Set.insert "Pear" |> Set.insert "Banana" countValues = Set.len fewItemSet expect countValues == 3 ``` #### len **Type Annotation** ```roc Set * -> U64 ``` **Description** Counts the number of values in a given `Set`. ```roc fewItemSet = Set.empty {} |> Set.insert "Apple" |> Set.insert "Pear" |> Set.insert "Banana" countValues = Set.len fewItemSet expect countValues == 3 ``` #### capacity **Type Annotation** ```roc Set * -> U64 ``` **Description** Returns the max number of elements the set can hold before requiring a rehash. ```roc foodSet = Set.empty {} |> Set.insert "apple" capacityOfSet = Set.capacity foodSet ``` #### isEmpty **Type Annotation** ```roc Set * -> Bool ``` **Description** Check if the set is empty. ```roc Set.isEmpty (Set.empty {} |> Set.insert 42) Set.isEmpty (Set.empty {}) ``` #### remove **Type Annotation** ```roc Set k, k -> Set k ``` **Description** Removes the value from the given `Set`. ```roc 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 **Type Annotation** ```roc Set k, k -> Bool ``` **Description** Test if a value is in the `Set`. ```roc Fruit : [Apple, Pear, Banana] fruit : Set Fruit fruit = Set.single Apple |> Set.insert Pear hasApple = Set.contains fruit Apple hasBanana = Set.contains fruit Banana expect hasApple == Bool.true expect hasBanana == Bool.false ``` #### toList **Type Annotation** ```roc Set k -> List k ``` **Description** Retrieve the values in a `Set` as a `List`. ```roc numbers : Set U64 numbers = Set.fromList [1,2,3,4,5] values = [1,2,3,4,5] expect Set.toList numbers == values ``` #### fromList **Type Annotation** ```roc List k -> Set k ``` **Description** Create a `Set` from a `List` of values. ```roc values = Set.empty {} |> Set.insert Banana |> Set.insert Apple |> Set.insert Pear expect Set.fromList [Pear, Apple, Banana] == values ``` #### union **Type Annotation** ```roc Set k, Set k -> Set k ``` **Description** Combine two `Set` collection by keeping the [union](https://en.wikipedia.org/wiki/Union_(set_theory)) of all the values pairs. This means that all of the values in both `Set`s will be combined. ```roc set1 = Set.single Left set2 = Set.single Right expect Set.union set1 set2 == Set.fromList [Left, Right] ``` #### intersection **Type Annotation** ```roc Set k, Set k -> Set k ``` **Description** Combine two `Set`s by keeping the [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory)) of all the values pairs. This means that we keep only those values that are in both `Set`s. ```roc set1 = Set.fromList [Left, Other] set2 = Set.fromList [Left, Right] expect Set.intersection set1 set2 == Set.single Left ``` #### difference **Type Annotation** ```roc 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](https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement) of the values. This means that we will be left with only those values that are in the first and not in the second. ```roc first = Set.fromList [Left, Right, Up, Down] second = Set.fromList [Left, Right] expect Set.difference first second == Set.fromList [Up, Down] ``` #### walk **Type Annotation** ```roc Set k, state, (state, k -> state) -> state ``` **Description** Iterate through the values of a given `Set` and build a value. ```roc values = Set.fromList ["March", "April", "May"] startsWithLetterM = \month -> when Str.toUtf8 month is ['M', ..] -> Bool.true _ -> Bool.false reduce = \state, k -> if startsWithLetterM k then state + 1 else state result = Set.walk values 0 reduce expect result == 2 ``` #### map **Type Annotation** ```roc 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. #### joinMap **Type Annotation** ```roc 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 `concatMap` in other languages. #### walkUntil **Type Annotation** ```roc 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. ```roc numbers = Set.fromList [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.walkUntil numbers NotFound find42 expect result == FoundTheAnswer ``` #### keepIf **Type Annotation** ```roc 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`. ```roc expect Set.fromList [1,2,3,4,5] |> Set.keepIf \k -> k >= 3 |> Bool.isEq (Set.fromList [3,4,5]) ``` #### dropIf **Type Annotation** ```roc 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`. ```roc expect Set.fromList [1,2,3,4,5] |> Set.dropIf \k -> k >= 3 |> Bool.isEq (Set.fromList [1,2]) ``` ### Decode #### DecodeError **Type Annotation** ```roc [TooShort] ``` **Description** Error types when decoding a `List U8` of utf-8 bytes using a [Decoder] #### DecodeResult **Type Annotation** **Description** Return type of a [Decoder]. This can be useful when creating a [custom](#custom) decoder or when using [fromBytesPartial](#fromBytesPartial). For example writing unit tests, such as; ```roc expect input = "\"hello\", " |> Str.toUtf8 actual = Decode.fromBytesPartial input Json.json expected = Ok "hello" actual.result == expected ``` #### Decoder **Type Annotation** **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 **Type Annotation** ```roc implements decoder : Decoder val fmt where val implements Decoding, fmt implements DecoderFormatting ``` **Description** Definition of the [Decoding] ability #### DecoderFormatting **Type Annotation** ```roc 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 **Type Annotation** ```roc (List U8, fmt -> DecodeResult val) -> Decoder val fmt where fmt implements DecoderFormatting ``` **Description** Build a custom [Decoder] function. For example the implementation of `decodeBool` could be defined as follows; ```roc decodeBool = Decode.custom \bytes, @Json {} -> when bytes is ['f', 'a', 'l', 's', 'e', ..] -> { result: Ok Bool.false, rest: List.dropFirst bytes 5 } ['t', 'r', 'u', 'e', ..] -> { result: Ok Bool.true, rest: List.dropFirst bytes 4 } _ -> { result: Err TooShort, rest: bytes } ``` #### decodeWith **Type Annotation** ```roc 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 #### fromBytesPartial **Type Annotation** ```roc List U8, fmt -> DecodeResult val where val implements Decoding, fmt implements DecoderFormatting ``` **Description** Decode a `List U8` utf-8 bytes and return a [DecodeResult](#DecodeResult) ```roc expect input = "\"hello\", " |> Str.toUtf8 actual = Decode.fromBytesPartial input Json.json expected = Ok "hello" actual.result == expected ``` #### fromBytes **Type Annotation** ```roc 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)`. ```roc expect input = "\"hello\", " |> Str.toUtf8 actual = Decode.fromBytes input Json.json expected = Ok "hello" actual == expected ``` #### mapResult **Type Annotation** ```roc DecodeResult a, (a -> b) -> DecodeResult b ``` **Description** Transform the `val` of a [DecodeResult] ### Encode #### Encoder **Type Annotation** #### Encoding **Type Annotation** ```roc implements toEncoder : val -> Encoder fmt where val implements Encoding, fmt implements EncoderFormatting ``` #### EncoderFormatting **Type Annotation** ```roc 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 **Type Annotation** ```roc (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting ``` **Description** Creates a custom encoder from a given function. ```roc expect # Appends the byte 42 customEncoder = Encode.custom (\bytes, _fmt -> List.append bytes 42) actual = Encode.appendWith [] customEncoder Core.json expected = [42] # Expected result is a list with a single byte, 42 actual == expected ``` #### appendWith **Type Annotation** ```roc List U8, Encoder fmt, fmt -> List U8 where fmt implements EncoderFormatting ``` #### append **Type Annotation** ```roc 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. ```roc expect actual = Encode.append [] { foo: 43 } Core.json expected = Str.toUtf8 """{"foo":43}""" actual == expected ``` #### toBytes **Type Annotation** ```roc 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. ```roc expect fooRec = { foo: 42 } actual = Encode.toBytes fooRec Core.json expected = Str.toUtf8 """{"foo":42}""" actual == expected ``` ### Hash #### Hash **Type Annotation** ```roc implements hash : hasher, a -> hasher where a implements Hash, hasher implements Hasher ``` **Description** A value that can be hashed. #### Hasher **Type Annotation** ```roc implements addBytes : a, List U8 -> a where a implements Hasher addU8 : a, U8 -> a where a implements Hasher addU16 : a, U16 -> a where a implements Hasher addU32 : a, U32 -> a where a implements Hasher addU64 : a, U64 -> a where a implements Hasher addU128 : 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. #### hashStrBytes **Type Annotation** **Description** Adds a string into a [Hasher] by hashing its UTF-8 bytes. #### hashList **Type Annotation** **Description** Adds a list of [Hash]able elements to a [Hasher] by hashing each element. #### hashBool **Type Annotation** ```roc a, Bool -> a where a implements Hasher ``` **Description** Adds a single [Bool] to a hasher. #### hashI8 **Type Annotation** ```roc a, I8 -> a where a implements Hasher ``` **Description** Adds a single I8 to a hasher. #### hashI16 **Type Annotation** ```roc a, I16 -> a where a implements Hasher ``` **Description** Adds a single I16 to a hasher. #### hashI32 **Type Annotation** ```roc a, I32 -> a where a implements Hasher ``` **Description** Adds a single I32 to a hasher. #### hashI64 **Type Annotation** ```roc a, I64 -> a where a implements Hasher ``` **Description** Adds a single I64 to a hasher. #### hashI128 **Type Annotation** ```roc a, I128 -> a where a implements Hasher ``` **Description** Adds a single I128 to a hasher. #### hashDec **Type Annotation** ```roc a, Dec -> a where a implements Hasher ``` **Description** Adds a single [Dec] to a hasher. #### hashUnordered **Type Annotation** **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 **Type Annotation** ```roc 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. ```roc expect Box.unbox (Box.box "Stack Faster") == "Stack Faster" ``` #### unbox **Type Annotation** ```roc Box a -> a ``` **Description** Returns a boxed value. ```roc expect Box.unbox (Box.box "Stack Faster") == "Stack Faster" ``` ### Inspect #### KeyValWalker **Type Annotation** ```roc collection, state, (state, key, val -> state) -> state ``` #### ElemWalker **Type Annotation** ```roc collection, state, (state, elem -> state) -> state ``` #### InspectFormatter **Type Annotation** ```roc 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 ``` #### Inspector **Type Annotation** #### custom **Type Annotation** ```roc (f -> f) -> Inspector f where f implements InspectFormatter ``` #### apply **Type Annotation** ```roc Inspector f, f -> f where f implements InspectFormatter ``` #### Inspect **Type Annotation** ```roc implements toInspector : val -> Inspector f where val implements Inspect, f implements InspectFormatter ``` #### inspect **Type Annotation** ```roc val -> f where val implements Inspect, f implements InspectFormatter ``` #### toStr **Type Annotation** ```roc val -> Str where val implements Inspect ``` ### Task #### Task **Type Annotation** **Description** A Task represents an effect; an interaction with state outside your Roc program, such as the terminal's standard output, or a file. #### forever **Type Annotation** ```roc Task a err -> Task * err ``` **Description** Run a task repeatedly, until it fails with `err`. Note that this task does not return a success value. #### loop **Type Annotation** ```roc state, (state -> Task [ Step state, Done done ] err) -> Task done err ``` **Description** Run a task repeatedly, until it fails with `err` or completes with `done`. ``` sum = Task.loop! 0 \total -> numResult = Stdin.line |> Task.result! |> Result.try Str.toU64 when numResult is Ok num -> Task.ok (Step (total + num)) Err (StdinErr EndOfFile) -> Task.ok (Done total) Err InvalidNumStr -> Task.err NonNumberGiven ``` #### ok **Type Annotation** ```roc a -> Task a * ``` **Description** Create a task that always succeeds with the value provided. ``` # Always succeeds with "Louis" getName : Task.Task Str * getName = Task.ok "Louis" ``` #### err **Type Annotation** ```roc a -> Task * a ``` **Description** Create a task that always fails with the error provided. ``` # Always fails with the tag `CustomError Str` customError : Str -> Task.Task {} [CustomError Str] customError = \err -> Task.err (CustomError err) ``` #### attempt **Type Annotation** ```roc Task a b, (Result a b -> Task c d) -> Task c d ``` **Description** Transform a given Task with a function that handles the success or error case and returns another task based on that. This is useful for chaining tasks together or performing error handling and recovery. Consider the following task: `canFail : Task {} [Failure, AnotherFail, YetAnotherFail]` We can use [attempt] to handle the failure cases using the following: ``` Task.attempt canFail \result -> when result is Ok Success -> Stdout.line "Success!" Err Failure -> Stdout.line "Oops, failed!" Err AnotherFail -> Stdout.line "Ooooops, another failure!" Err YetAnotherFail -> Stdout.line "Really big oooooops, yet again!" ``` Here we know that the `canFail` task may fail, and so we use `Task.attempt` to convert the task to a `Result` and then use pattern matching to handle the success and possible failure cases. #### await **Type Annotation** ```roc Task a b, (a -> Task c b) -> Task c b ``` **Description** Take the success value from a given [Task] and use that to generate a new [Task]. We can [await] Task results with callbacks: ``` Task.await (Stdin.line "What's your name?") \name -> Stdout.line "Your name is: $(name)" ``` Or we can more succinctly use the `!` bang operator, which desugars to [await]: ``` name = Stdin.line! "What's your name?" Stdout.line "Your name is: $(name)" ``` #### onErr **Type Annotation** ```roc Task a b, (b -> Task a c) -> Task a c ``` **Description** Take the error value from a given [Task] and use that to generate a new [Task]. ``` # Prints "Something went wrong!" to standard error if `canFail` fails. canFail |> Task.onErr \_ -> Stderr.line "Something went wrong!" ``` #### map **Type Annotation** ```roc Task a c, (a -> b) -> Task b c ``` **Description** Transform the success value of a given [Task] with a given function. ``` # Succeeds with a value of "Bonjour Louis!" Task.ok "Louis" |> Task.map (\name -> "Bonjour $(name)!") ``` #### mapErr **Type Annotation** ```roc Task c a, (a -> b) -> Task c b ``` **Description** Transform the error value of a given [Task] with a given function. ``` # Ignore the fail value, and map it to the tag `CustomError` canFail |> Task.mapErr \_ -> CustomError ``` #### fromResult **Type Annotation** ```roc Result a b -> Task a b ``` **Description** Use a Result among other Tasks by converting it into a [Task]. #### batch **Type Annotation** ```roc Task a c -> Task (a -> b) c -> Task b c ``` **Description** Apply a task to another task applicatively. This can be used with [ok] to build a [Task] that returns a record. The following example returns a Record with two fields, `apples` and `oranges`, each of which is a `List Str`. If it fails it returns the tag `NoFruitAvailable`. ``` getFruitBasket : Task { apples : List Str, oranges : List Str } [NoFruitAvailable] getFruitBasket = Task.ok { apples: <- getFruit Apples |> Task.batch, oranges: <- getFruit Oranges |> Task.batch, } ``` #### sequence **Type Annotation** ```roc List (Task ok err) -> Task (List ok) err ``` **Description** Apply each task in a list sequentially, and return a list of the resulting values. Each task will be awaited before beginning the next task. ``` fetchAuthorTasks : List (Task Author [DbError]) getAuthors : Task (List Author) [DbError] getAuthors = Task.sequence fetchAuthorTasks ``` #### forEach **Type Annotation** ```roc List a, (a -> Task {} b) -> Task {} b ``` **Description** Apply a task repeatedly for each item in a list ``` authors : List Author saveAuthor : Author -> Task {} [DbError] saveAuthors : Task (List Author) [DbError] saveAuthors = Task.forEach authors saveAuthor ``` #### result **Type Annotation** ```roc Task ok err -> Task (Result ok err) * ``` **Description** Transform a task that can either succeed with `ok`, or fail with `err`, into a task that succeeds with `Result ok err`. This is useful when chaining tasks using the `!` suffix. For example: ``` # Path.roc checkFile : Str -> Task [Good, Bad] [IOError] # main.roc when checkFile "/usr/local/bin/roc" |> Task.result! is Ok Good -> "..." Ok Bad -> "..." Err IOError -> "..." ```