aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gleam/atom.gleam118
-rw-r--r--src/gleam/base.gleam66
-rw-r--r--src/gleam/bit_builder.gleam183
-rw-r--r--src/gleam/bit_string.gleam126
-rw-r--r--src/gleam/bool.gleam372
-rw-r--r--src/gleam/dynamic.gleam1259
-rw-r--r--src/gleam/float.gleam422
-rw-r--r--src/gleam/function.gleam122
-rw-r--r--src/gleam/int.gleam408
-rw-r--r--src/gleam/io.gleam140
-rw-r--r--src/gleam/iterator.gleam1822
-rw-r--r--src/gleam/list.gleam2810
-rw-r--r--src/gleam/map.gleam594
-rw-r--r--src/gleam/option.gleam412
-rw-r--r--src/gleam/order.gleam178
-rw-r--r--src/gleam/os.gleam107
-rw-r--r--src/gleam/pair.gleam114
-rw-r--r--src/gleam/queue.gleam472
-rw-r--r--src/gleam/regex.gleam220
-rw-r--r--src/gleam/result.gleam508
-rw-r--r--src/gleam/set.gleam390
-rw-r--r--src/gleam/should.gleam54
-rw-r--r--src/gleam/string.gleam892
-rw-r--r--src/gleam/string_builder.gleam336
-rw-r--r--src/gleam/uri.gleam626
-rw-r--r--src/gleam_stdlib.erl16
-rw-r--r--src/gleam_stdlib.js0
27 files changed, 6438 insertions, 6329 deletions
diff --git a/src/gleam/atom.gleam b/src/gleam/atom.gleam
index e85f5d5..2d96053 100644
--- a/src/gleam/atom.gleam
+++ b/src/gleam/atom.gleam
@@ -1,62 +1,64 @@
-/// Atom is a special string-like data-type that is most commonly used for
-/// interfacing with code written in other BEAM languages such as Erlang and
-/// Elixir. It is preferable to define your own custom types to use instead of
-/// atoms where possible.
-///
-/// Atoms are not used much in typical Gleam code!
-///
-/// ## Creating atoms
-///
-/// We can create atoms with the the [`create_from_string`](#create_from_string)
-/// function, though we must be careful when doing so as atoms are never
-/// garbage collected. If we create too many atoms (for example, if we convert
-/// user input into atoms) we may hit the max limit of atoms and cause the
-/// virtual machine to crash.
-///
-pub external type Atom
+if erlang {
+ /// Atom is a special string-like data-type that is most commonly used for
+ /// interfacing with code written in other BEAM languages such as Erlang and
+ /// Elixir. It is preferable to define your own custom types to use instead of
+ /// atoms where possible.
+ ///
+ /// Atoms are not used much in typical Gleam code!
+ ///
+ /// ## Creating atoms
+ ///
+ /// We can create atoms with the the [`create_from_string`](#create_from_string)
+ /// function, though we must be careful when doing so as atoms are never
+ /// garbage collected. If we create too many atoms (for example, if we convert
+ /// user input into atoms) we may hit the max limit of atoms and cause the
+ /// virtual machine to crash.
+ ///
+ pub external type Atom
-/// An error returned when no atom is found in the virtual machine's atom table
-/// for a given string when calling the [`from_string`](#from_string) function.
-pub type FromStringError {
- AtomNotLoaded
-}
+ /// An error returned when no atom is found in the virtual machine's atom table
+ /// for a given string when calling the [`from_string`](#from_string) function.
+ pub type FromStringError {
+ AtomNotLoaded
+ }
-/// Finds an existing Atom for the given String.
-///
-/// If no atom is found in the virtual machine's atom table for the String then
-/// an error is returned.
-///
-/// ## Examples
-///
-/// > from_string("ok")
-/// Ok(create_from_string("ok"))
-///
-/// > from_string("some_new_atom")
-/// Error(AtomNotLoaded)
-///
-pub external fn from_string(String) -> Result(Atom, FromStringError) =
- "gleam_stdlib" "atom_from_string"
+ /// Finds an existing Atom for the given String.
+ ///
+ /// If no atom is found in the virtual machine's atom table for the String then
+ /// an error is returned.
+ ///
+ /// ## Examples
+ ///
+ /// > from_string("ok")
+ /// Ok(create_from_string("ok"))
+ ///
+ /// > from_string("some_new_atom")
+ /// Error(AtomNotLoaded)
+ ///
+ pub external fn from_string(String) -> Result(Atom, FromStringError) =
+ "gleam_stdlib" "atom_from_string"
-/// Creates an atom from a string, inserting a new value into the virtual
-/// machine's atom table if an atom does not already exist for the given
-/// string.
-///
-/// We must be careful when using this function as there is a limit to the
-/// number of atom that can fit in the virtual machine's atom table. Never
-/// convert user input into atoms as filling the atom table will cause the
-/// virtual machine to crash!
-///
-pub external fn create_from_string(String) -> Atom =
- "gleam_stdlib" "atom_create_from_string"
+ /// Creates an atom from a string, inserting a new value into the virtual
+ /// machine's atom table if an atom does not already exist for the given
+ /// string.
+ ///
+ /// We must be careful when using this function as there is a limit to the
+ /// number of atom that can fit in the virtual machine's atom table. Never
+ /// convert user input into atoms as filling the atom table will cause the
+ /// virtual machine to crash!
+ ///
+ pub external fn create_from_string(String) -> Atom =
+ "gleam_stdlib" "atom_create_from_string"
-/// Retuns a `String` corresponding to the text representation of the given
-/// `Atom`.
-///
-/// ## Examples
-///
-/// > let ok_atom = create_from_string("ok")
-/// > to_string(ok_atom)
-/// "ok"
-///
-pub external fn to_string(Atom) -> String =
- "gleam_stdlib" "atom_to_string"
+ /// Retuns a `String` corresponding to the text representation of the given
+ /// `Atom`.
+ ///
+ /// ## Examples
+ ///
+ /// > let ok_atom = create_from_string("ok")
+ /// > to_string(ok_atom)
+ /// "ok"
+ ///
+ pub external fn to_string(Atom) -> String =
+ "gleam_stdlib" "atom_to_string"
+}
diff --git a/src/gleam/base.gleam b/src/gleam/base.gleam
index c1c3824..5ca741e 100644
--- a/src/gleam/base.gleam
+++ b/src/gleam/base.gleam
@@ -1,41 +1,43 @@
-import gleam/bit_string.{BitString}
-import gleam/string
+if erlang {
+ import gleam/bit_string.{BitString}
+ import gleam/string
-external fn erl_encode64(BitString) -> String =
- "base64" "encode"
+ external fn erl_encode64(BitString) -> String =
+ "base64" "encode"
-external fn erl_decode64(String) -> Result(BitString, Nil) =
- "gleam_stdlib" "base_decode64"
+ external fn erl_decode64(String) -> Result(BitString, Nil) =
+ "gleam_stdlib" "base_decode64"
-/// Encodes a BitString into a base 64 encoded string.
-pub fn encode64(input: BitString, padding: Bool) -> String {
- let encoded = erl_encode64(input)
- case padding {
- True -> encoded
- False -> string.replace(encoded, "=", "")
+ /// Encodes a BitString into a base 64 encoded string.
+ pub fn encode64(input: BitString, padding: Bool) -> String {
+ let encoded = erl_encode64(input)
+ case padding {
+ True -> encoded
+ False -> string.replace(encoded, "=", "")
+ }
}
-}
-/// Decodes a base 64 encoded string into a BitString.
-pub fn decode64(encoded: String) -> Result(BitString, Nil) {
- let padded = case bit_string.byte_size(bit_string.from_string(encoded)) % 4 {
- 0 -> encoded
- n -> string.append(encoded, string.repeat("=", 4 - n))
+ /// Decodes a base 64 encoded string into a BitString.
+ pub fn decode64(encoded: String) -> Result(BitString, Nil) {
+ let padded = case bit_string.byte_size(bit_string.from_string(encoded)) % 4 {
+ 0 -> encoded
+ n -> string.append(encoded, string.repeat("=", 4 - n))
+ }
+ erl_decode64(padded)
}
- erl_decode64(padded)
-}
-/// Encodes a BitString into a base 64 encoded string with URL and filename safe alphabet.
-pub fn url_encode64(input: BitString, padding: Bool) -> String {
- encode64(input, padding)
- |> string.replace("+", "-")
- |> string.replace("/", "_")
-}
+ /// Encodes a BitString into a base 64 encoded string with URL and filename safe alphabet.
+ pub fn url_encode64(input: BitString, padding: Bool) -> String {
+ encode64(input, padding)
+ |> string.replace("+", "-")
+ |> string.replace("/", "_")
+ }
-/// Decodes a base 64 encoded string with URL and filename safe alphabet into a BitString.
-pub fn url_decode64(encoded: String) -> Result(BitString, Nil) {
- encoded
- |> string.replace("-", "+")
- |> string.replace("_", "/")
- |> decode64()
+ /// Decodes a base 64 encoded string with URL and filename safe alphabet into a BitString.
+ pub fn url_decode64(encoded: String) -> Result(BitString, Nil) {
+ encoded
+ |> string.replace("-", "+")
+ |> string.replace("_", "/")
+ |> decode64()
+ }
}
diff --git a/src/gleam/bit_builder.gleam b/src/gleam/bit_builder.gleam
index d69fea5..738c79c 100644
--- a/src/gleam/bit_builder.gleam
+++ b/src/gleam/bit_builder.gleam
@@ -1,102 +1,107 @@
-import gleam/bit_string.{BitString}
-import gleam/string_builder.{StringBuilder}
+if erlang {
+ import gleam/bit_string.{BitString}
+ import gleam/string_builder.{StringBuilder}
-/// BitBuilder is a type used for efficiently concatenating bits to create bit
-/// strings.
-///
-/// If we append one bit string to another the bit strings must be copied to a
-/// new location in memory so that they can sit together. This behaviour
-/// enables efficient reading of the string but copying can be expensive,
-/// especially if we want to join many bit strings together.
-///
-/// BitBuilder is different in that it can be joined together in constant
-/// time using minimal memory, and then can be efficiently converted to a
-/// bit string using the `to_bit_string` function.
-///
-pub external type BitBuilder
+ /// BitBuilder is a type used for efficiently concatenating bits to create bit
+ /// strings.
+ ///
+ /// If we append one bit string to another the bit strings must be copied to a
+ /// new location in memory so that they can sit together. This behaviour
+ /// enables efficient reading of the string but copying can be expensive,
+ /// especially if we want to join many bit strings together.
+ ///
+ /// BitBuilder is different in that it can be joined together in constant
+ /// time using minimal memory, and then can be efficiently converted to a
+ /// bit string using the `to_bit_string` function.
+ ///
+ pub external type BitBuilder
-/// Prepends a bit string to the start of a builder.
-///
-/// Runs in constant time.
-///
-pub external fn prepend(to: BitBuilder, prefix: BitString) -> BitBuilder =
- "gleam_stdlib" "iodata_prepend"
+ /// Prepends a bit string to the start of a builder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn prepend(to: BitBuilder, prefix: BitString) -> BitBuilder =
+ "gleam_stdlib" "iodata_prepend"
-/// Appends a bit string to the end of a builder.
-///
-/// Runs in constant time.
-///
-pub external fn append(to: BitBuilder, suffix: BitString) -> BitBuilder =
- "gleam_stdlib" "iodata_append"
+ /// Appends a bit string to the end of a builder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn append(to: BitBuilder, suffix: BitString) -> BitBuilder =
+ "gleam_stdlib" "iodata_append"
-/// Prepends a builder onto the start of another.
-///
-/// Runs in constant time.
-///
-pub external fn prepend_builder(
- to: BitBuilder,
- prefix: BitBuilder,
-) -> BitBuilder =
- "gleam_stdlib" "iodata_prepend"
+ /// Prepends a builder onto the start of another.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn prepend_builder(
+ to: BitBuilder,
+ prefix: BitBuilder,
+ ) -> BitBuilder =
+ "gleam_stdlib" "iodata_prepend"
-/// Appends a builder onto the end of another.
-///
-/// Runs in constant time.
-///
-pub external fn append_builder(to: BitBuilder, suffix: BitBuilder) -> BitBuilder =
- "gleam_stdlib" "iodata_append"
+ /// Appends a builder onto the end of another.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn append_builder(
+ to: BitBuilder,
+ suffix: BitBuilder,
+ ) -> BitBuilder =
+ "gleam_stdlib" "iodata_append"
-/// Prepends a string onto the start of a builder.
-///
-/// Runs in constant time.
-///
-pub external fn prepend_string(to: BitBuilder, prefix: String) -> BitBuilder =
- "gleam_stdlib" "iodata_prepend"
+ /// Prepends a string onto the start of a builder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn prepend_string(to: BitBuilder, prefix: String) -> BitBuilder =
+ "gleam_stdlib" "iodata_prepend"
-/// Appends a string onto the end of a builder.
-///
-/// Runs in constant time.
-///
-pub external fn append_string(to: BitBuilder, suffix: String) -> BitBuilder =
- "gleam_stdlib" "iodata_append"
+ /// Appends a string onto the end of a builder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn append_string(to: BitBuilder, suffix: String) -> BitBuilder =
+ "gleam_stdlib" "iodata_append"
-/// Joins a list of builders into a single builders.
-///
-/// Runs in constant time.
-///
-pub external fn concat(List(BitBuilder)) -> BitBuilder =
- "gleam_stdlib" "identity"
+ /// Joins a list of builders into a single builders.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn concat(List(BitBuilder)) -> BitBuilder =
+ "gleam_stdlib" "identity"
-/// Creates a new builder from a string.
-///
-/// Runs in constant time.
-///
-pub external fn from_string(String) -> BitBuilder =
- "gleam_stdlib" "wrap_list"
+ /// Creates a new builder from a string.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn from_string(String) -> BitBuilder =
+ "gleam_stdlib" "wrap_list"
-/// Creates a new builder from a string builder.
-///
-/// Runs in constant time.
-///
-pub external fn from_string_builder(StringBuilder) -> BitBuilder =
- "gleam_stdlib" "identity"
+ /// Creates a new builder from a string builder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn from_string_builder(StringBuilder) -> BitBuilder =
+ "gleam_stdlib" "identity"
-/// Creates a new builder from a bit string.
-///
-/// Runs in constant time.
-///
-pub external fn from_bit_string(BitString) -> BitBuilder =
- "gleam_stdlib" "wrap_list"
+ /// Creates a new builder from a bit string.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn from_bit_string(BitString) -> BitBuilder =
+ "gleam_stdlib" "wrap_list"
-/// Turns an builder into a bit string.
-///
-/// This function is implemented natively by the virtual machine and is highly
-/// optimised.
-///
-pub external fn to_bit_string(BitBuilder) -> BitString =
- "erlang" "list_to_bitstring"
+ /// Turns an builder into a bit string.
+ ///
+ /// This function is implemented natively by the virtual machine and is highly
+ /// optimised.
+ ///
+ pub external fn to_bit_string(BitBuilder) -> BitString =
+ "erlang" "list_to_bitstring"
-/// Returns the size of the builder's content in bytes.
-///
-pub external fn byte_size(BitBuilder) -> Int =
- "erlang" "iolist_size"
+ /// Returns the size of the builder's content in bytes.
+ ///
+ pub external fn byte_size(BitBuilder) -> Int =
+ "erlang" "iolist_size"
+}
diff --git a/src/gleam/bit_string.gleam b/src/gleam/bit_string.gleam
index 4e10268..835ff7c 100644
--- a/src/gleam/bit_string.gleam
+++ b/src/gleam/bit_string.gleam
@@ -2,77 +2,79 @@
//// The BitString type should be used instead of a String type when not utf8
//// encoded.
-pub type BitString =
- BitString
+if erlang {
+ pub type BitString =
+ BitString
-/// Converts a UTF-8 String type into a raw BitString type.
-///
-pub external fn from_string(String) -> BitString =
- "gleam_stdlib" "identity"
+ /// Converts a UTF-8 String type into a raw BitString type.
+ ///
+ pub external fn from_string(String) -> BitString =
+ "gleam_stdlib" "identity"
-/// Returns an integer which is the number of bytes in the bit string.
-///
-pub external fn byte_size(BitString) -> Int =
- "erlang" "byte_size"
+ /// Returns an integer which is the number of bytes in the bit string.
+ ///
+ pub external fn byte_size(BitString) -> Int =
+ "erlang" "byte_size"
-/// Creates a new bit string by joining two binaries.
-///
-/// ## Examples
-///
-/// > append(to: from_string("butter"), suffix: from_string("fly"))
-/// from_string("butterfly")
-///
-pub external fn append(first: BitString, second: BitString) -> BitString =
- "gleam_stdlib" "bit_string_append"
+ /// Creates a new bit string by joining two binaries.
+ ///
+ /// ## Examples
+ ///
+ /// > append(to: from_string("butter"), suffix: from_string("fly"))
+ /// from_string("butterfly")
+ ///
+ pub external fn append(first: BitString, second: BitString) -> BitString =
+ "gleam_stdlib" "bit_string_append"
-/// Extracts part of a bit string.
-///
-/// BitString part will start at given position and continue up to specified
-/// length.
-/// A negative length can be used to extract bytes at the end of a bit string.
-///
-pub external fn part(
- string: BitString,
- position: Int,
- length: Int,
-) -> Result(BitString, Nil) =
- "gleam_stdlib" "bit_string_part_"
+ /// Extracts part of a bit string.
+ ///
+ /// BitString part will start at given position and continue up to specified
+ /// length.
+ /// A negative length can be used to extract bytes at the end of a bit string.
+ ///
+ pub external fn part(
+ string: BitString,
+ position: Int,
+ length: Int,
+ ) -> Result(BitString, Nil) =
+ "gleam_stdlib" "bit_string_part_"
-/// Converts an integer to unsigned 32 bits.
-///
-/// Returns an error if integer is less than zero or equal to or larger than
-/// 2^32.
-///
-pub external fn int_to_u32(Int) -> Result(BitString, Nil) =
- "gleam_stdlib" "bit_string_int_to_u32"
+ /// Converts an integer to unsigned 32 bits.
+ ///
+ /// Returns an error if integer is less than zero or equal to or larger than
+ /// 2^32.
+ ///
+ pub external fn int_to_u32(Int) -> Result(BitString, Nil) =
+ "gleam_stdlib" "bit_string_int_to_u32"
-/// Converts unsigned 32 bits to an integer.
-///
-/// Returns an error if the bit string is not 32 bits in length.
-///
-pub external fn int_from_u32(BitString) -> Result(Int, Nil) =
- "gleam_stdlib" "bit_string_int_from_u32"
+ /// Converts unsigned 32 bits to an integer.
+ ///
+ /// Returns an error if the bit string is not 32 bits in length.
+ ///
+ pub external fn int_from_u32(BitString) -> Result(Int, Nil) =
+ "gleam_stdlib" "bit_string_int_from_u32"
-/// Tests to see whether a bit string is valid UTF-8.
-///
-pub fn is_utf8(bits: BitString) -> Bool {
- case bits {
- <<>> -> True
- <<_:utf8, rest:binary>> -> is_utf8(rest)
- _ -> False
+ /// Tests to see whether a bit string is valid UTF-8.
+ ///
+ pub fn is_utf8(bits: BitString) -> Bool {
+ case bits {
+ <<>> -> True
+ <<_:utf8, rest:binary>> -> is_utf8(rest)
+ _ -> False
+ }
}
-}
-external fn unsafe_to_string(BitString) -> String =
- "gleam_stdlib" "identity"
+ external fn unsafe_to_string(BitString) -> String =
+ "gleam_stdlib" "identity"
-/// Converts a bit string to a string.
-///
-/// Returns an error if the bit string is invalid UTF-8 data.
-///
-pub fn to_string(bits: BitString) -> Result(String, Nil) {
- case is_utf8(bits) {
- True -> Ok(unsafe_to_string(bits))
- False -> Error(Nil)
+ /// Converts a bit string to a string.
+ ///
+ /// Returns an error if the bit string is invalid UTF-8 data.
+ ///
+ pub fn to_string(bits: BitString) -> Result(String, Nil) {
+ case is_utf8(bits) {
+ True -> Ok(unsafe_to_string(bits))
+ False -> Error(Nil)
+ }
}
}
diff --git a/src/gleam/bool.gleam b/src/gleam/bool.gleam
index 684aa2f..e25f7b5 100644
--- a/src/gleam/bool.gleam
+++ b/src/gleam/bool.gleam
@@ -1,205 +1,207 @@
-import gleam/order.{Order}
+if erlang {
+ import gleam/order.{Order}
-/// A type with two possible values, True and False. Used to indicate whether
-/// things are... true or false!
-///
-/// Often is it clearer and offers more type safety to define a custom type
-/// than to use Bool. For example, rather than having a `is_teacher: Bool`
-/// field consider having a `role: SchoolRole` field where SchoolRole is a custom
-/// type that can be either Student or Teacher.
-///
-pub type Bool =
- Bool
+ /// A type with two possible values, True and False. Used to indicate whether
+ /// things are... true or false!
+ ///
+ /// Often is it clearer and offers more type safety to define a custom type
+ /// than to use Bool. For example, rather than having a `is_teacher: Bool`
+ /// field consider having a `role: SchoolRole` field where SchoolRole is a custom
+ /// type that can be either Student or Teacher.
+ ///
+ pub type Bool =
+ Bool
-/// Returns the opposite bool value.
-///
-/// This is the same as the `!` or `not` operators in some other languages.
-///
-/// ## Examples
-///
-/// > negate(True)
-/// False
-///
-/// > negate(False)
-/// True
-///
-pub fn negate(bool: Bool) -> Bool {
- case bool {
- True -> False
- False -> True
+ /// Returns the opposite bool value.
+ ///
+ /// This is the same as the `!` or `not` operators in some other languages.
+ ///
+ /// ## Examples
+ ///
+ /// > negate(True)
+ /// False
+ ///
+ /// > negate(False)
+ /// True
+ ///
+ pub fn negate(bool: Bool) -> Bool {
+ case bool {
+ True -> False
+ False -> True
+ }
}
-}
-/// Returns the nor of two bools
-///
-/// ## Examples
-///
-/// > nor(False, False)
-/// True
-///
-/// > nor(False, True)
-/// False
-///
-/// > nor(True, False)
-/// False
-///
-/// > nor(True, True)
-/// False
-///
-pub fn nor(a: Bool, b: Bool) -> Bool {
- case a, b {
- False, False -> True
- False, True -> False
- True, False -> False
- True, True -> False
+ /// Returns the nor of two bools
+ ///
+ /// ## Examples
+ ///
+ /// > nor(False, False)
+ /// True
+ ///
+ /// > nor(False, True)
+ /// False
+ ///
+ /// > nor(True, False)
+ /// False
+ ///
+ /// > nor(True, True)
+ /// False
+ ///
+ pub fn nor(a: Bool, b: Bool) -> Bool {
+ case a, b {
+ False, False -> True
+ False, True -> False
+ True, False -> False
+ True, True -> False
+ }
}
-}
-/// Returns the nand of two bools
-///
-/// ## Examples
-///
-/// > nand(False, False)
-/// True
-///
-/// > nand(False, True)
-/// True
-///
-/// > nand(True, False)
-/// True
-///
-/// > nand(True, True)
-/// False
-///
-pub fn nand(a: Bool, b: Bool) -> Bool {
- case a, b {
- False, False -> True
- False, True -> True
- True, False -> True
- True, True -> False
+ /// Returns the nand of two bools
+ ///
+ /// ## Examples
+ ///
+ /// > nand(False, False)
+ /// True
+ ///
+ /// > nand(False, True)
+ /// True
+ ///
+ /// > nand(True, False)
+ /// True
+ ///
+ /// > nand(True, True)
+ /// False
+ ///
+ pub fn nand(a: Bool, b: Bool) -> Bool {
+ case a, b {
+ False, False -> True
+ False, True -> True
+ True, False -> True
+ True, True -> False
+ }
}
-}
-/// Returns the exclusive or of two bools
-///
-/// ## Examples
-///
-/// > exclusive_or(False, False)
-/// False
-///
-/// > exclusive_or(False, True)
-/// True
-///
-/// > exclusive_or(True, False)
-/// True
-///
-/// > exclusive_or(True, True)
-/// False
-///
-pub fn exclusive_or(a: Bool, b: Bool) -> Bool {
- case a, b {
- False, False -> False
- False, True -> True
- True, False -> True
- True, True -> False
+ /// Returns the exclusive or of two bools
+ ///
+ /// ## Examples
+ ///
+ /// > exclusive_or(False, False)
+ /// False
+ ///
+ /// > exclusive_or(False, True)
+ /// True
+ ///
+ /// > exclusive_or(True, False)
+ /// True
+ ///
+ /// > exclusive_or(True, True)
+ /// False
+ ///
+ pub fn exclusive_or(a: Bool, b: Bool) -> Bool {
+ case a, b {
+ False, False -> False
+ False, True -> True
+ True, False -> True
+ True, True -> False
+ }
}
-}
-/// Returns the exclusive nor of two bools
-///
-/// ## Examples
-///
-/// > exclusive_nor(False, False)
-/// True
-///
-/// > exclusive_nor(False, True)
-/// False
-///
-/// > exclusive_nor(True, False)
-/// False
-///
-/// > exclusive_nor(True, True)
-/// True
-///
-pub fn exclusive_nor(a: Bool, b: Bool) -> Bool {
- case a, b {
- False, False -> True
- False, True -> False
- True, False -> False
- True, True -> True
+ /// Returns the exclusive nor of two bools
+ ///
+ /// ## Examples
+ ///
+ /// > exclusive_nor(False, False)
+ /// True
+ ///
+ /// > exclusive_nor(False, True)
+ /// False
+ ///
+ /// > exclusive_nor(True, False)
+ /// False
+ ///
+ /// > exclusive_nor(True, True)
+ /// True
+ ///
+ pub fn exclusive_nor(a: Bool, b: Bool) -> Bool {
+ case a, b {
+ False, False -> True
+ False, True -> False
+ True, False -> False
+ True, True -> True
+ }
}
-}
-/// Compares two bools and returns the first values Order to the second.
-///
-/// ## Examples
-///
-/// > import gleam/order
-/// > compare(True, False)
-/// order.Gt
-///
-pub fn compare(a: Bool, with b: Bool) -> Order {
- case a, b {
- True, True -> order.Eq
- True, False -> order.Gt
- False, False -> order.Eq
- False, True -> order.Lt
+ /// Compares two bools and returns the first values Order to the second.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/order
+ /// > compare(True, False)
+ /// order.Gt
+ ///
+ pub fn compare(a: Bool, with b: Bool) -> Order {
+ case a, b {
+ True, True -> order.Eq
+ True, False -> order.Gt
+ False, False -> order.Eq
+ False, True -> order.Lt
+ }
}
-}
-/// Returns True if either bool value is True.
-///
-/// ## Examples
-///
-/// > max(True, False)
-/// True
-///
-/// > max(False, True)
-/// True
-///
-/// > max(False, False)
-/// False
-///
-pub fn max(a: Bool, b: Bool) -> Bool {
- case a {
- True -> True
- False -> b
+ /// Returns True if either bool value is True.
+ ///
+ /// ## Examples
+ ///
+ /// > max(True, False)
+ /// True
+ ///
+ /// > max(False, True)
+ /// True
+ ///
+ /// > max(False, False)
+ /// False
+ ///
+ pub fn max(a: Bool, b: Bool) -> Bool {
+ case a {
+ True -> True
+ False -> b
+ }
}
-}
-/// Returns False if either bool value is False.
-///
-/// ## Examples
-///
-/// > max(True, False)
-/// False
-///
-/// > max(False, True)
-/// False
-///
-/// > max(False, False)
-/// False
-///
-pub fn min(a: Bool, b: Bool) -> Bool {
- case a {
- False -> False
- True -> b
+ /// Returns False if either bool value is False.
+ ///
+ /// ## Examples
+ ///
+ /// > max(True, False)
+ /// False
+ ///
+ /// > max(False, True)
+ /// False
+ ///
+ /// > max(False, False)
+ /// False
+ ///
+ pub fn min(a: Bool, b: Bool) -> Bool {
+ case a {
+ False -> False
+ True -> b
+ }
}
-}
-/// Returns a numeric representation of the given bool.
-///
-/// ## Examples
-///
-/// > to_int(True)
-/// 1
-///
-/// > to_int(False)
-/// 0
-///
-pub fn to_int(bool: Bool) -> Int {
- case bool {
- False -> 0
- True -> 1
+ /// Returns a numeric representation of the given bool.
+ ///
+ /// ## Examples
+ ///
+ /// > to_int(True)
+ /// 1
+ ///
+ /// > to_int(False)
+ /// 0
+ ///
+ pub fn to_int(bool: Bool) -> Int {
+ case bool {
+ False -> 0
+ True -> 1
+ }
}
}
diff --git a/src/gleam/dynamic.gleam b/src/gleam/dynamic.gleam
index 162045f..be2c9b7 100644
--- a/src/gleam/dynamic.gleam
+++ b/src/gleam/dynamic.gleam
@@ -1,641 +1,646 @@
-import gleam/atom
-import gleam/bit_string.{BitString}
-import gleam/list
-import gleam/map.{Map}
-import gleam/option.{None, Option, Some}
-import gleam/result
-import gleam/string_builder
-
-/// `Dynamic` data is data that we don't know the type of yet.
-/// We likely get data like this from interop with Erlang, or from
-/// IO with the outside world.
-pub external type Dynamic
-
-pub type Decoder(t) =
- fn(Dynamic) -> Result(t, String)
-
-/// Converts any Gleam data into `Dynamic` data.
-///
-pub external fn from(a) -> Dynamic =
- "gleam_stdlib" "identity"
-
-/// Unsafely casts a Dynamic value into any other type.
-///
-/// This is an escape hatch for the type system that may be useful when wrapping
-/// native Erlang APIs. It is to be used as a last measure only!
-///
-/// If you can avoid using this function, do!
-///
-pub external fn unsafe_coerce(Dynamic) -> a =
- "gleam_stdlib" "identity"
-
-/// Checks to see whether a Dynamic value is a bit_string, and return the bit_string if
-/// it is.
-///
-/// ## Examples
-///
-/// > bit_string(from("Hello")) == bit_string.from_string("Hello")
-/// True
-///
-/// > bit_string(from(123))
-/// Error("Expected a BitString, got `123`")
-///
-pub external fn bit_string(from: Dynamic) -> Result(BitString, String) =
- "gleam_stdlib" "decode_bit_string"
-
-/// Checks to see whether a Dynamic value is a string, and return the string if
-/// it is.
-///
-/// ## Examples
-///
-/// > string(from("Hello"))
-/// Ok("Hello")
-///
-/// > string(from(123))
-/// Error("Expected a String, got `123`")
-///
-pub fn string(from: Dynamic) -> Result(String, String) {
- bit_string(from)
- |> result.then(fn(raw) {
- case bit_string.to_string(raw) {
- Ok(string) -> Ok(string)
- Error(Nil) -> Error("Expected a string, got a bit_string")
- }
- })
-}
+if erlang {
+ import gleam/atom
+ import gleam/bit_string.{BitString}
+ import gleam/list
+ import gleam/map.{Map}
+ import gleam/option.{None, Option, Some}
+ import gleam/result
+ import gleam/string_builder
+
+ /// `Dynamic` data is data that we don't know the type of yet.
+ /// We likely get data like this from interop with Erlang, or from
+ /// IO with the outside world.
+ pub external type Dynamic
+
+ pub type Decoder(t) =
+ fn(Dynamic) -> Result(t, String)
+
+ /// Converts any Gleam data into `Dynamic` data.
+ ///
+ pub external fn from(a) -> Dynamic =
+ "gleam_stdlib" "identity"
+
+ /// Unsafely casts a Dynamic value into any other type.
+ ///
+ /// This is an escape hatch for the type system that may be useful when wrapping
+ /// native Erlang APIs. It is to be used as a last measure only!
+ ///
+ /// If you can avoid using this function, do!
+ ///
+ pub external fn unsafe_coerce(Dynamic) -> a =
+ "gleam_stdlib" "identity"
+
+ /// Checks to see whether a Dynamic value is a bit_string, and return the bit_string if
+ /// it is.
+ ///
+ /// ## Examples
+ ///
+ /// > bit_string(from("Hello")) == bit_string.from_string("Hello")
+ /// True
+ ///
+ /// > bit_string(from(123))
+ /// Error("Expected a BitString, got `123`")
+ ///
+ pub external fn bit_string(from: Dynamic) -> Result(BitString, String) =
+ "gleam_stdlib" "decode_bit_string"
+
+ /// Checks to see whether a Dynamic value is a string, and return the string if
+ /// it is.
+ ///
+ /// ## Examples
+ ///
+ /// > string(from("Hello"))
+ /// Ok("Hello")
+ ///
+ /// > string(from(123))
+ /// Error("Expected a String, got `123`")
+ ///
+ pub fn string(from: Dynamic) -> Result(String, String) {
+ bit_string(from)
+ |> result.then(fn(raw) {
+ case bit_string.to_string(raw) {
+ Ok(string) -> Ok(string)
+ Error(Nil) -> Error("Expected a string, got a bit_string")
+ }
+ })
+ }
-/// Checks to see whether a Dynamic value is an int, and return the int if it
-/// is.
-///
-/// ## Examples
-///
-/// > int(from(123))
-/// Ok(123)
-///
-/// > int(from("Hello"))
-/// Error("Expected an Int, got `\"Hello World\"`")
-///
-pub external fn int(from: Dynamic) -> Result(Int, String) =
- "gleam_stdlib" "decode_int"
-
-/// Checks to see whether a Dynamic value is an float, and return the float if
-/// it is.
-///
-/// ## Examples
-///
-/// > float(from(2.0))
-/// Ok(2.0)
-///
-/// > float(from(123))
-/// Error("Expected a Float, got `123`")
-///
-pub external fn float(from: Dynamic) -> Result(Float, String) =
- "gleam_stdlib" "decode_float"
-
-/// Checks to see whether a Dynamic value is an atom, and return the atom if
-/// it is.
-///
-/// ## Examples
-///
-/// > import gleam/atom
-/// > atom(from(atom.create_from_string("hello")))
-/// OK("hello")
-///
-/// > atom(from(123))
-/// Error("Expected an Atom, got `123`")
-///
-pub external fn atom(from: Dynamic) -> Result(atom.Atom, String) =
- "gleam_stdlib" "decode_atom"
-
-/// Checks to see whether a Dynamic value is an bool, and return the bool if
-/// it is.
-///
-/// ## Examples
-///
-/// > bool(from(True))
-/// Ok(True)
-///
-/// > bool(from(123))
-/// Error("Expected a Bool, got `123`")
-///
-pub external fn bool(from: Dynamic) -> Result(Bool, String) =
- "gleam_stdlib" "decode_bool"
-
-/// Checks to see whether a Dynamic value is a function that takes no arguments,
-/// and return the function if it is.
-///
-/// ## Examples
-///
-/// > import gleam/result
-/// > let f = fn() { 1 }
-/// > thunk(from(f)) |> result.is_ok
-/// True
-///
-/// > thunk(from(123))
-/// Error("Expected a zero arity function, got `123`")
-///
-pub external fn thunk(from: Dynamic) -> Result(fn() -> Dynamic, String) =
- "gleam_stdlib" "decode_thunk"
-
-/// Checks to see whether a Dynamic value is a list, and return the list if it
-/// is.
-///
-/// If you wish to decode all the elements in the list use the `typed_list`
-/// instead.
-///
-/// ## Examples
-///
-/// > list(from(["a", "b", "c"]))
-/// Ok([from("a"), from("b"), from("c")])
-///
-/// > list(1)
-/// Error("Expected an Int, got a binary")
-///
-pub external fn list(from: Dynamic) -> Result(List(Dynamic), String) =
- "gleam_stdlib" "decode_list"
-
-/// Checks to see whether a Dynamic value is a result, and return the result if
-/// it is
-///
-/// ## Examples
-///
-/// > result(from(Ok(1)))
-/// Ok(Ok(from(1)))
-///
-/// > result(from(Error("boom")))
-/// Ok(Error(from("boom")))
-///
-/// > result(from(123))
-/// Error("Expected a 2 element tuple, got an int")
-///
-pub fn result(from: Dynamic) -> Result(Result(Dynamic, Dynamic), String) {
- try #(key, val) = tuple2(from)
-
- try tag = atom(key)
- let ok_atom = atom.create_from_string("ok")
- let error_atom = atom.create_from_string("error")
- case tag {
- tag if tag == ok_atom -> Ok(Ok(val))
- tag if tag == error_atom -> Ok(Error(val))
- tag ->
- "Expected a tag of \"ok\" or \"error\", got \""
- |> string_builder.from_string
- |> string_builder.append(atom.to_string(tag))
- |> string_builder.append("\"")
- |> string_builder.to_string
- |> Error
+ /// Checks to see whether a Dynamic value is an int, and return the int if it
+ /// is.
+ ///
+ /// ## Examples
+ ///
+ /// > int(from(123))
+ /// Ok(123)
+ ///
+ /// > int(from("Hello"))
+ /// Error("Expected an Int, got `\"Hello World\"`")
+ ///
+ pub external fn int(from: Dynamic) -> Result(Int, String) =
+ "gleam_stdlib" "decode_int"
+
+ /// Checks to see whether a Dynamic value is an float, and return the float if
+ /// it is.
+ ///
+ /// ## Examples
+ ///
+ /// > float(from(2.0))
+ /// Ok(2.0)
+ ///
+ /// > float(from(123))
+ /// Error("Expected a Float, got `123`")
+ ///
+ pub external fn float(from: Dynamic) -> Result(Float, String) =
+ "gleam_stdlib" "decode_float"
+
+ /// Checks to see whether a Dynamic value is an atom, and return the atom if
+ /// it is.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/atom
+ /// > atom(from(atom.create_from_string("hello")))
+ /// OK("hello")
+ ///
+ /// > atom(from(123))
+ /// Error("Expected an Atom, got `123`")
+ ///
+ pub external fn atom(from: Dynamic) -> Result(atom.Atom, String) =
+ "gleam_stdlib" "decode_atom"
+
+ /// Checks to see whether a Dynamic value is an bool, and return the bool if
+ /// it is.
+ ///
+ /// ## Examples
+ ///
+ /// > bool(from(True))
+ /// Ok(True)
+ ///
+ /// > bool(from(123))
+ /// Error("Expected a Bool, got `123`")
+ ///
+ pub external fn bool(from: Dynamic) -> Result(Bool, String) =
+ "gleam_stdlib" "decode_bool"
+
+ /// Checks to see whether a Dynamic value is a function that takes no arguments,
+ /// and return the function if it is.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/result
+ /// > let f = fn() { 1 }
+ /// > thunk(from(f)) |> result.is_ok
+ /// True
+ ///
+ /// > thunk(from(123))
+ /// Error("Expected a zero arity function, got `123`")
+ ///
+ pub external fn thunk(from: Dynamic) -> Result(fn() -> Dynamic, String) =
+ "gleam_stdlib" "decode_thunk"
+
+ /// Checks to see whether a Dynamic value is a list, and return the list if it
+ /// is.
+ ///
+ /// If you wish to decode all the elements in the list use the `typed_list`
+ /// instead.
+ ///
+ /// ## Examples
+ ///
+ /// > list(from(["a", "b", "c"]))
+ /// Ok([from("a"), from("b"), from("c")])
+ ///
+ /// > list(1)
+ /// Error("Expected an Int, got a binary")
+ ///
+ pub external fn list(from: Dynamic) -> Result(List(Dynamic), String) =
+ "gleam_stdlib" "decode_list"
+
+ /// Checks to see whether a Dynamic value is a result, and return the result if
+ /// it is
+ ///
+ /// ## Examples
+ ///
+ /// > result(from(Ok(1)))
+ /// Ok(Ok(from(1)))
+ ///
+ /// > result(from(Error("boom")))
+ /// Ok(Error(from("boom")))
+ ///
+ /// > result(from(123))
+ /// Error("Expected a 2 element tuple, got an int")
+ ///
+ pub fn result(from: Dynamic) -> Result(Result(Dynamic, Dynamic), String) {
+ try #(key, val) = tuple2(from)
+
+ try tag = atom(key)
+ let ok_atom = atom.create_from_string("ok")
+ let error_atom = atom.create_from_string("error")
+ case tag {
+ tag if tag == ok_atom -> Ok(Ok(val))
+ tag if tag == error_atom -> Ok(Error(val))
+ tag ->
+ "Expected a tag of \"ok\" or \"error\", got \""
+ |> string_builder.from_string
+ |> string_builder.append(atom.to_string(tag))
+ |> string_builder.append("\"")
+ |> string_builder.to_string
+ |> Error
+ }
}
-}
-/// Checks to see whether a Dynamic value is a result of a particular type, and
-/// return the result if it is
-///
-/// The `ok` and `error` arguments are decoders for decoding the `Ok` and
-/// `Error` values of the result.
-///
-/// ## Examples
-///
-/// > typed_result(of: from(Ok(1)), ok: int, error: string)
-/// Ok(Ok(1))
-///
-/// > typed_result(of: from(Error("boom")), ok: int, error: string)
-/// Ok(Error("boom"))
-///
-/// > typed_result(of: from(123), ok: int, error: string)
-/// Error("Expected a 2 element tuple, got an int")
-///
-pub fn typed_result(
- of dynamic: Dynamic,
- ok decode_ok: Decoder(a),
- error decode_error: Decoder(e),
-) -> Result(Result(a, e), String) {
- try inner_result = result(dynamic)
-
- case inner_result {
- Ok(raw) ->
- raw
- |> decode_ok
- |> result.map(Ok)
- Error(raw) ->
- raw
- |> decode_error
- |> result.map(Error)
+ /// Checks to see whether a Dynamic value is a result of a particular type, and
+ /// return the result if it is
+ ///
+ /// The `ok` and `error` arguments are decoders for decoding the `Ok` and
+ /// `Error` values of the result.
+ ///
+ /// ## Examples
+ ///
+ /// > typed_result(of: from(Ok(1)), ok: int, error: string)
+ /// Ok(Ok(1))
+ ///
+ /// > typed_result(of: from(Error("boom")), ok: int, error: string)
+ /// Ok(Error("boom"))
+ ///
+ /// > typed_result(of: from(123), ok: int, error: string)
+ /// Error("Expected a 2 element tuple, got an int")
+ ///
+ pub fn typed_result(
+ of dynamic: Dynamic,
+ ok decode_ok: Decoder(a),
+ error decode_error: Decoder(e),
+ ) -> Result(Result(a, e), String) {
+ try inner_result = result(dynamic)
+
+ case inner_result {
+ Ok(raw) ->
+ raw
+ |> decode_ok
+ |> result.map(Ok)
+ Error(raw) ->
+ raw
+ |> decode_error
+ |> result.map(Error)
+ }
}
-}
-/// Checks to see whether a Dynamic value is a list of a particular type, and
-/// return the list if it is.
-///
-/// The second argument is a decoder function used to decode the elements of
-/// the list. The list is only decoded if all elements in the list can be
-/// successfully decoded using this function.
-///
-/// If you do not wish to decode all the elements in the list use the `list`
-/// function instead.
-///
-/// ## Examples
-///
-/// > typed_list(from(["a", "b", "c"]), of: string)
-/// Ok(["a", "b", "c"])
-///
-/// > typed_list(from([1, 2, 3]), of: string)
-/// Error("Expected an Int, got a binary")
-///
-/// > typed_list(from("ok"), of: string)
-/// Error("Expected a List, got a binary")
-///
-pub fn typed_list(
- from dynamic: Dynamic,
- of decoder_type: fn(Dynamic) -> Result(inner, String),
-) -> Result(List(inner), String) {
- dynamic
- |> list
- |> result.then(list.try_map(_, decoder_type))
-}
+ /// Checks to see whether a Dynamic value is a list of a particular type, and
+ /// return the list if it is.
+ ///
+ /// The second argument is a decoder function used to decode the elements of
+ /// the list. The list is only decoded if all elements in the list can be
+ /// successfully decoded using this function.
+ ///
+ /// If you do not wish to decode all the elements in the list use the `list`
+ /// function instead.
+ ///
+ /// ## Examples
+ ///
+ /// > typed_list(from(["a", "b", "c"]), of: string)
+ /// Ok(["a", "b", "c"])
+ ///
+ /// > typed_list(from([1, 2, 3]), of: string)
+ /// Error("Expected an Int, got a binary")
+ ///
+ /// > typed_list(from("ok"), of: string)
+ /// Error("Expected a List, got a binary")
+ ///
+ pub fn typed_list(
+ from dynamic: Dynamic,
+ of decoder_type: fn(Dynamic) -> Result(inner, String),
+ ) -> Result(List(inner), String) {
+ dynamic
+ |> list
+ |> result.then(list.try_map(_, decoder_type))
+ }
-/// Checks to see if a Dynamic value is an Option of a particular type, and return
-/// the Option if it is.
-///
-/// The second argument is a decoder function used to decode the elements of
-/// the list. The list is only decoded if all elements in the list can be
-/// successfully decoded using this function.
-///
-/// ## Examples
-///
-/// > option(from("Hello"), string)
-/// Ok(Some("Hello"))
-///
-/// > option(from(atom.from_string("null")), string)
-/// Ok(None)
-///
-/// > option(from(123), string)
-/// Error("Expected a bit_string, got an int")
-///
-pub fn option(
- from dynamic: Dynamic,
- of decoder: Decoder(inner),
-) -> Result(Option(inner), String) {
- let Ok(null) = atom.from_string("null")
- case atom(dynamic), decoder(dynamic) {
- Ok(atom), _ if atom == null -> Ok(None)
- _, Ok(result) -> Ok(Some(result))
- _, Error(msg) -> Error(msg)
+ /// Checks to see if a Dynamic value is an Option of a particular type, and return
+ /// the Option if it is.
+ ///
+ /// The second argument is a decoder function used to decode the elements of
+ /// the list. The list is only decoded if all elements in the list can be
+ /// successfully decoded using this function.
+ ///
+ /// ## Examples
+ ///
+ /// > option(from("Hello"), string)
+ /// Ok(Some("Hello"))
+ ///
+ /// > option(from(atom.from_string("null")), string)
+ /// Ok(None)
+ ///
+ /// > option(from(123), string)
+ /// Error("Expected a bit_string, got an int")
+ ///
+ pub fn option(
+ from dynamic: Dynamic,
+ of decoder: Decoder(inner),
+ ) -> Result(Option(inner), String) {
+ let Ok(null) = atom.from_string("null")
+ case atom(dynamic), decoder(dynamic) {
+ Ok(atom), _ if atom == null -> Ok(None)
+ _, Ok(result) -> Ok(Some(result))
+ _, Error(msg) -> Error(msg)
+ }
}
-}
-/// Checks to see if a Dynamic value is a map with a specific field, and return
-/// the value of the field if it is.
-///
-/// This will not succeed on a record.
-///
-/// ## Examples
-///
-/// > import gleam/map
-/// > field(from(map.new("Hello", "World")), "Hello")
-/// Ok(Dynamic)
-///
-/// > field(from(123), "Hello")
-/// Error("Expected a map with key `\"Hello\"`, got an Int")
-///
-pub external fn field(from: Dynamic, named: a) -> Result(Dynamic, String) =
- "gleam_stdlib" "decode_field"
-
-/// Checks to see if the Dynamic value is a tuple large enough to have a certain
-/// index, and return the value of that index if it is.
-///
-/// ## Examples
-///
-/// > element(from(#(1, 2)), 0)
-/// Ok(from(1))
-///
-/// > element(from(#(1, 2)), 2)
-/// Error("Expected a tuple of at least 3 size, got a tuple of 2 size")
-///
-/// > element(from(""), 2)
-/// Error("Expected a tuple, got a binary")
-///
-pub external fn element(from: Dynamic, position: Int) -> Result(Dynamic, String) =
- "gleam_stdlib" "decode_element"
-
-/// Checks to see if the Dynamic value is a 2 element tuple.
-///
-/// If you do not wish to decode all the elements in the tuple use the
-/// `typed_tuple2` function instead.
-///
-/// ## Examples
-///
-/// > tuple2(from(#(1, 2)))
-/// Ok(#(from(1), from(2)))
-///
-/// > tuple2(from(#(1, 2, 3)))
-/// Error("Expected a 2 element tuple")
-///
-/// > tuple2(from(""))
-/// Error("Expected a tuple, got a binary")
-///
-pub external fn tuple2(from: Dynamic) -> Result(#(Dynamic, Dynamic), String) =
- "gleam_stdlib" "decode_tuple2"
-
-/// Checks to see if the Dynamic value is a 2 element tuple containing two
-/// specifically typed elements.
-///
-/// If you wish to decode all the elements in the list use the `typed_tuple2`
-/// instead.
-///
-/// ## Examples
-///
-/// > typed_tuple2(from(#(1, 2)), int, int)
-/// Ok(#(1, 2))
-///
-/// > typed_tuple2(from(#(1, 2.0)), int, float)
-/// Ok(#(1, 2.0))
-///
-/// > typed_tuple2(from(#(1, 2, 3)), int, float)
-/// Error("Expected a 2 element tuple, got a 3 element tuple")
-///
-/// > typed_tuple2(from(""), int, float)
-/// Error("Expected a tuple, got a binary")
-///
-pub fn typed_tuple2(
- from tup: Dynamic,
- first decode_first: Decoder(a),
- second decode_second: Decoder(b),
-) -> Result(#(a, b), String) {
- try #(first, second) = tuple2(tup)
- try a = decode_first(first)
- try b = decode_second(second)
- Ok(#(a, b))
-}
+ /// Checks to see if a Dynamic value is a map with a specific field, and return
+ /// the value of the field if it is.
+ ///
+ /// This will not succeed on a record.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/map
+ /// > field(from(map.new("Hello", "World")), "Hello")
+ /// Ok(Dynamic)
+ ///
+ /// > field(from(123), "Hello")
+ /// Error("Expected a map with key `\"Hello\"`, got an Int")
+ ///
+ pub external fn field(from: Dynamic, named: a) -> Result(Dynamic, String) =
+ "gleam_stdlib" "decode_field"
+
+ /// Checks to see if the Dynamic value is a tuple large enough to have a certain
+ /// index, and return the value of that index if it is.
+ ///
+ /// ## Examples
+ ///
+ /// > element(from(#(1, 2)), 0)
+ /// Ok(from(1))
+ ///
+ /// > element(from(#(1, 2)), 2)
+ /// Error("Expected a tuple of at least 3 size, got a tuple of 2 size")
+ ///
+ /// > element(from(""), 2)
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub external fn element(
+ from: Dynamic,
+ position: Int,
+ ) -> Result(Dynamic, String) =
+ "gleam_stdlib" "decode_element"
+
+ /// Checks to see if the Dynamic value is a 2 element tuple.
+ ///
+ /// If you do not wish to decode all the elements in the tuple use the
+ /// `typed_tuple2` function instead.
+ ///
+ /// ## Examples
+ ///
+ /// > tuple2(from(#(1, 2)))
+ /// Ok(#(from(1), from(2)))
+ ///
+ /// > tuple2(from(#(1, 2, 3)))
+ /// Error("Expected a 2 element tuple")
+ ///
+ /// > tuple2(from(""))
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub external fn tuple2(from: Dynamic) -> Result(#(Dynamic, Dynamic), String) =
+ "gleam_stdlib" "decode_tuple2"
+
+ /// Checks to see if the Dynamic value is a 2 element tuple containing two
+ /// specifically typed elements.
+ ///
+ /// If you wish to decode all the elements in the list use the `typed_tuple2`
+ /// instead.
+ ///
+ /// ## Examples
+ ///
+ /// > typed_tuple2(from(#(1, 2)), int, int)
+ /// Ok(#(1, 2))
+ ///
+ /// > typed_tuple2(from(#(1, 2.0)), int, float)
+ /// Ok(#(1, 2.0))
+ ///
+ /// > typed_tuple2(from(#(1, 2, 3)), int, float)
+ /// Error("Expected a 2 element tuple, got a 3 element tuple")
+ ///
+ /// > typed_tuple2(from(""), int, float)
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub fn typed_tuple2(
+ from tup: Dynamic,
+ first decode_first: Decoder(a),
+ second decode_second: Decoder(b),
+ ) -> Result(#(a, b), String) {
+ try #(first, second) = tuple2(tup)
+ try a = decode_first(first)
+ try b = decode_second(second)
+ Ok(#(a, b))
+ }
-/// Checks to see if the Dynamic value is a 3 element tuple.
-///
-/// If you do not wish to decode all the elements in the tuple use the
-/// `typed_tuple3` function instead.
-///
-/// ## Examples
-///
-/// > tuple3(from(#(1, 2, 3)))
-/// Ok(#(from(1), from(2), from(3)))
-///
-/// > tuple3(from(#(1, 2)))
-/// Error("Expected a 3 element tuple")
-///
-/// > tuple3(from(""))
-/// Error("Expected a tuple, got a binary")
-///
-pub external fn tuple3(
- from: Dynamic,
-) -> Result(#(Dynamic, Dynamic, Dynamic), String) =
- "gleam_stdlib" "decode_tuple3"
-
-/// Checks to see if the Dynamic value is a 3 element tuple containing two
-/// specifically typed elements.
-///
-/// If you wish to decode all the elements in the list use the `typed_tuple3`
-/// instead.
-///
-/// ## Examples
-///
-/// > typed_tuple3(from(#(1, 2, 3)), int, int, int)
-/// Ok(#(1, 2, 3))
-///
-/// > typed_tuple3(from(#(1, 2.0, "3")), int, float, string)
-/// Ok(#(1, 2.0, "3"))
-///
-/// > typed_tuple3(from(#(1, 2)), int, float, string)
-/// Error("Expected a 3 element tuple, got a 2 element tuple")
-///
-/// > typed_tuple3(from(""), int, float, string)
-/// Error("Expected a tuple, got a binary")
-///
-pub fn typed_tuple3(
- from tup: Dynamic,
- first decode_first: Decoder(a),
- second decode_second: Decoder(b),
- third decode_third: Decoder(c),
-) -> Result(#(a, b, c), String) {
- try #(first, second, third) = tuple3(tup)
- try a = decode_first(first)
- try b = decode_second(second)
- try c = decode_third(third)
- Ok(#(a, b, c))
-}
+ /// Checks to see if the Dynamic value is a 3 element tuple.
+ ///
+ /// If you do not wish to decode all the elements in the tuple use the
+ /// `typed_tuple3` function instead.
+ ///
+ /// ## Examples
+ ///
+ /// > tuple3(from(#(1, 2, 3)))
+ /// Ok(#(from(1), from(2), from(3)))
+ ///
+ /// > tuple3(from(#(1, 2)))
+ /// Error("Expected a 3 element tuple")
+ ///
+ /// > tuple3(from(""))
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub external fn tuple3(
+ from: Dynamic,
+ ) -> Result(#(Dynamic, Dynamic, Dynamic), String) =
+ "gleam_stdlib" "decode_tuple3"
+
+ /// Checks to see if the Dynamic value is a 3 element tuple containing two
+ /// specifically typed elements.
+ ///
+ /// If you wish to decode all the elements in the list use the `typed_tuple3`
+ /// instead.
+ ///
+ /// ## Examples
+ ///
+ /// > typed_tuple3(from(#(1, 2, 3)), int, int, int)
+ /// Ok(#(1, 2, 3))
+ ///
+ /// > typed_tuple3(from(#(1, 2.0, "3")), int, float, string)
+ /// Ok(#(1, 2.0, "3"))
+ ///
+ /// > typed_tuple3(from(#(1, 2)), int, float, string)
+ /// Error("Expected a 3 element tuple, got a 2 element tuple")
+ ///
+ /// > typed_tuple3(from(""), int, float, string)
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub fn typed_tuple3(
+ from tup: Dynamic,
+ first decode_first: Decoder(a),
+ second decode_second: Decoder(b),
+ third decode_third: Decoder(c),
+ ) -> Result(#(a, b, c), String) {
+ try #(first, second, third) = tuple3(tup)
+ try a = decode_first(first)
+ try b = decode_second(second)
+ try c = decode_third(third)
+ Ok(#(a, b, c))
+ }
-/// Checks to see if the Dynamic value is a 4 element tuple.
-///
-/// If you do not wish to decode all the elements in the tuple use the
-/// `typed_tuple4` function instead.
-///
-/// ## Examples
-///
-/// > tuple4(from(#(1, 2, 3, 4)))
-/// Ok(#(from(1), from(2), from(3), from(4)))
-///
-/// > tuple4(from(#(1, 2)))
-/// Error("Expected a 4 element tuple")
-///
-/// > tuple4(from(""))
-/// Error("Expected a tuple, got a binary")
-///
-pub external fn tuple4(
- from: Dynamic,
-) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic), String) =
- "gleam_stdlib" "decode_tuple4"
-
-/// Checks to see if the Dynamic value is a 4 element tuple containing two
-/// specifically typed elements.
-///
-/// If you wish to decode all the elements in the list use the `typed_tuple4`
-/// instead.
-///
-/// ## Examples
-///
-/// > typed_tuple4(from(#(1, 2, 3, 4)), int, int, int, int)
-/// Ok(#(1, 2, 3, 4))
-///
-/// > typed_tuple4(from(#(1, 2.0, "3", 4)), int, float, string, int)
-/// Ok(#(1, 2.0, "3", 4))
-///
-/// > typed_tuple4(from(#(1, 2)), int, float, string, int)
-/// Error("Expected a 4 element tuple, got a 2 element tuple")
-///
-/// > typed_tuple4(from(""), int, float, string, int)
-/// Error("Expected a tuple, got a binary")
-///
-pub fn typed_tuple4(
- from tup: Dynamic,
- first decode_first: Decoder(a),
- second decode_second: Decoder(b),
- third decode_third: Decoder(c),
- fourth decode_fourth: Decoder(d),
-) -> Result(#(a, b, c, d), String) {
- try #(first, second, third, fourth) = tuple4(tup)
- try a = decode_first(first)
- try b = decode_second(second)
- try c = decode_third(third)
- try d = decode_fourth(fourth)
- Ok(#(a, b, c, d))
-}
+ /// Checks to see if the Dynamic value is a 4 element tuple.
+ ///
+ /// If you do not wish to decode all the elements in the tuple use the
+ /// `typed_tuple4` function instead.
+ ///
+ /// ## Examples
+ ///
+ /// > tuple4(from(#(1, 2, 3, 4)))
+ /// Ok(#(from(1), from(2), from(3), from(4)))
+ ///
+ /// > tuple4(from(#(1, 2)))
+ /// Error("Expected a 4 element tuple")
+ ///
+ /// > tuple4(from(""))
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub external fn tuple4(
+ from: Dynamic,
+ ) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic), String) =
+ "gleam_stdlib" "decode_tuple4"
+
+ /// Checks to see if the Dynamic value is a 4 element tuple containing two
+ /// specifically typed elements.
+ ///
+ /// If you wish to decode all the elements in the list use the `typed_tuple4`
+ /// instead.
+ ///
+ /// ## Examples
+ ///
+ /// > typed_tuple4(from(#(1, 2, 3, 4)), int, int, int, int)
+ /// Ok(#(1, 2, 3, 4))
+ ///
+ /// > typed_tuple4(from(#(1, 2.0, "3", 4)), int, float, string, int)
+ /// Ok(#(1, 2.0, "3", 4))
+ ///
+ /// > typed_tuple4(from(#(1, 2)), int, float, string, int)
+ /// Error("Expected a 4 element tuple, got a 2 element tuple")
+ ///
+ /// > typed_tuple4(from(""), int, float, string, int)
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub fn typed_tuple4(
+ from tup: Dynamic,
+ first decode_first: Decoder(a),
+ second decode_second: Decoder(b),
+ third decode_third: Decoder(c),
+ fourth decode_fourth: Decoder(d),
+ ) -> Result(#(a, b, c, d), String) {
+ try #(first, second, third, fourth) = tuple4(tup)
+ try a = decode_first(first)
+ try b = decode_second(second)
+ try c = decode_third(third)
+ try d = decode_fourth(fourth)
+ Ok(#(a, b, c, d))
+ }
-/// Checks to see if the Dynamic value is a 5 element tuple.
-///
-/// If you do not wish to decode all the elements in the tuple use the
-/// `typed_tuple5` function instead.
-///
-/// ## Examples
-///
-/// > tuple5(from(#(1, 2, 3, 4, 5)))
-/// Ok(#(from(1), from(2), from(3), from(4), from(5)))
-///
-/// > tuple5(from(#(1, 2)))
-/// Error("Expected a 5 element tuple")
-///
-/// > tuple5(from(""))
-/// Error("Expected a tuple, got a binary")
-///
-pub external fn tuple5(
- from: Dynamic,
-) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic, Dynamic), String) =
- "gleam_stdlib" "decode_tuple5"
-
-/// Checks to see if the Dynamic value is a 5 element tuple containing two
-/// specifically typed elements.
-///
-/// If you wish to decode all the elements in the list use the `typed_tuple5`
-/// instead.
-///
-/// ## Examples
-///
-/// > typed_tuple5(from(#(1, 2, 3, 4, 5)), int, int, int, int, int)
-/// Ok(#(1, 2, 3, 4, 5))
-///
-/// > typed_tuple5(from(#(1, 2.0, "3", 4, 5)), int, float, string, int, int)
-/// Ok(#(1, 2.0, "3", 4, 5))
-///
-/// > typed_tuple5(from(#(1, 2)), int, float, string, int, int)
-/// Error("Expected a 5 element tuple, got a 2 element tuple")
-///
-/// > typed_tuple5(from(""), int, float, string, int, int)
-/// Error("Expected a tuple, got a binary")
-///
-pub fn typed_tuple5(
- from tup: Dynamic,
- first decode_first: Decoder(a),
- second decode_second: Decoder(b),
- third decode_third: Decoder(c),
- fourth decode_fourth: Decoder(d),
- fifth decode_fifth: Decoder(e),
-) -> Result(#(a, b, c, d, e), String) {
- try #(first, second, third, fourth, fifth) = tuple5(tup)
- try a = decode_first(first)
- try b = decode_second(second)
- try c = decode_third(third)
- try d = decode_fourth(fourth)
- try e = decode_fifth(fifth)
- Ok(#(a, b, c, d, e))
-}
+ /// Checks to see if the Dynamic value is a 5 element tuple.
+ ///
+ /// If you do not wish to decode all the elements in the tuple use the
+ /// `typed_tuple5` function instead.
+ ///
+ /// ## Examples
+ ///
+ /// > tuple5(from(#(1, 2, 3, 4, 5)))
+ /// Ok(#(from(1), from(2), from(3), from(4), from(5)))
+ ///
+ /// > tuple5(from(#(1, 2)))
+ /// Error("Expected a 5 element tuple")
+ ///
+ /// > tuple5(from(""))
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub external fn tuple5(
+ from: Dynamic,
+ ) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic, Dynamic), String) =
+ "gleam_stdlib" "decode_tuple5"
+
+ /// Checks to see if the Dynamic value is a 5 element tuple containing two
+ /// specifically typed elements.
+ ///
+ /// If you wish to decode all the elements in the list use the `typed_tuple5`
+ /// instead.
+ ///
+ /// ## Examples
+ ///
+ /// > typed_tuple5(from(#(1, 2, 3, 4, 5)), int, int, int, int, int)
+ /// Ok(#(1, 2, 3, 4, 5))
+ ///
+ /// > typed_tuple5(from(#(1, 2.0, "3", 4, 5)), int, float, string, int, int)
+ /// Ok(#(1, 2.0, "3", 4, 5))
+ ///
+ /// > typed_tuple5(from(#(1, 2)), int, float, string, int, int)
+ /// Error("Expected a 5 element tuple, got a 2 element tuple")
+ ///
+ /// > typed_tuple5(from(""), int, float, string, int, int)
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub fn typed_tuple5(
+ from tup: Dynamic,
+ first decode_first: Decoder(a),
+ second decode_second: Decoder(b),
+ third decode_third: Decoder(c),
+ fourth decode_fourth: Decoder(d),
+ fifth decode_fifth: Decoder(e),
+ ) -> Result(#(a, b, c, d, e), String) {
+ try #(first, second, third, fourth, fifth) = tuple5(tup)
+ try a = decode_first(first)
+ try b = decode_second(second)
+ try c = decode_third(third)
+ try d = decode_fourth(fourth)
+ try e = decode_fifth(fifth)
+ Ok(#(a, b, c, d, e))
+ }
-/// Checks to see if the Dynamic value is a 6 element tuple.
-///
-/// If you do not wish to decode all the elements in the tuple use the
-/// `typed_tuple6` function instead.
-///
-/// ## Examples
-///
-/// > tuple6(from(#(1, 2, 3, 4, 5, 6)))
-/// Ok(#(from(1), from(2), from(3), from(4), from(5), from(6)))
-///
-/// > tuple6(from(#(1, 2)))
-/// Error("Expected a 6 element tuple")
-///
-/// > tuple6(from(""))
-/// Error("Expected a tuple, got a binary")
-///
-pub external fn tuple6(
- from: Dynamic,
-) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic, Dynamic, Dynamic), String) =
- "gleam_stdlib" "decode_tuple6"
-
-/// Checks to see if the Dynamic value is a 6 element tuple containing two
-/// specifically typed elements.
-///
-/// If you wish to decode all the elements in the list use the `typed_tuple6`
-/// instead.
-///
-/// ## Examples
-///
-/// > typed_tuple6(from(#(1, 2, 3, 4, 5, 6)), int, int, int, int, int, int)
-/// Ok(#(1, 2, 3, 4, 5, 6))
-///
-/// > typed_tuple6(from(#(1, 2.0, "3", 4, 5, 6)), int, float, string, int, int)
-/// Ok(#(1, 2.0, "3", 4, 5, 6))
-///
-/// > typed_tuple6(from(#(1, 2)), int, float, string, int, int, int)
-/// Error("Expected a 6 element tuple, got a 2 element tuple")
-///
-/// > typed_tuple6(from(""), int, float, string, int, int, int)
-/// Error("Expected a tuple, got a binary")
-///
-pub fn typed_tuple6(
- from tup: Dynamic,
- first decode_first: Decoder(a),
- second decode_second: Decoder(b),
- third decode_third: Decoder(c),
- fourth decode_fourth: Decoder(d),
- fifth decode_fifth: Decoder(e),
- sixth decode_sixth: Decoder(f),
-) -> Result(#(a, b, c, d, e, f), String) {
- try #(first, second, third, fourth, fifth, sixth) = tuple6(tup)
- try a = decode_first(first)
- try b = decode_second(second)
- try c = decode_third(third)
- try d = decode_fourth(fourth)
- try e = decode_fifth(fifth)
- try f = decode_sixth(sixth)
- Ok(#(a, b, c, d, e, f))
-}
+ /// Checks to see if the Dynamic value is a 6 element tuple.
+ ///
+ /// If you do not wish to decode all the elements in the tuple use the
+ /// `typed_tuple6` function instead.
+ ///
+ /// ## Examples
+ ///
+ /// > tuple6(from(#(1, 2, 3, 4, 5, 6)))
+ /// Ok(#(from(1), from(2), from(3), from(4), from(5), from(6)))
+ ///
+ /// > tuple6(from(#(1, 2)))
+ /// Error("Expected a 6 element tuple")
+ ///
+ /// > tuple6(from(""))
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub external fn tuple6(
+ from: Dynamic,
+ ) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic, Dynamic, Dynamic), String) =
+ "gleam_stdlib" "decode_tuple6"
+
+ /// Checks to see if the Dynamic value is a 6 element tuple containing two
+ /// specifically typed elements.
+ ///
+ /// If you wish to decode all the elements in the list use the `typed_tuple6`
+ /// instead.
+ ///
+ /// ## Examples
+ ///
+ /// > typed_tuple6(from(#(1, 2, 3, 4, 5, 6)), int, int, int, int, int, int)
+ /// Ok(#(1, 2, 3, 4, 5, 6))
+ ///
+ /// > typed_tuple6(from(#(1, 2.0, "3", 4, 5, 6)), int, float, string, int, int)
+ /// Ok(#(1, 2.0, "3", 4, 5, 6))
+ ///
+ /// > typed_tuple6(from(#(1, 2)), int, float, string, int, int, int)
+ /// Error("Expected a 6 element tuple, got a 2 element tuple")
+ ///
+ /// > typed_tuple6(from(""), int, float, string, int, int, int)
+ /// Error("Expected a tuple, got a binary")
+ ///
+ pub fn typed_tuple6(
+ from tup: Dynamic,
+ first decode_first: Decoder(a),
+ second decode_second: Decoder(b),
+ third decode_third: Decoder(c),
+ fourth decode_fourth: Decoder(d),
+ fifth decode_fifth: Decoder(e),
+ sixth decode_sixth: Decoder(f),
+ ) -> Result(#(a, b, c, d, e, f), String) {
+ try #(first, second, third, fourth, fifth, sixth) = tuple6(tup)
+ try a = decode_first(first)
+ try b = decode_second(second)
+ try c = decode_third(third)
+ try d = decode_fourth(fourth)
+ try e = decode_fifth(fifth)
+ try f = decode_sixth(sixth)
+ Ok(#(a, b, c, d, e, f))
+ }
-/// Checks to see if the Dynamic value is map.
-///
-/// ## Examples
-///
-/// > import gleam/map
-/// > map(from(map.new()))
-/// Ok(map.new())
-///
-/// > map(from(1))
-/// Error("Expected a 2 element tuple, got an int")
-///
-/// > map(from(""))
-/// Error("Expected a map, got a binary")
-///
-pub external fn map(from: Dynamic) -> Result(Map(Dynamic, Dynamic), String) =
- "gleam_stdlib" "decode_map"
-
-/// Joins multiple decoders into one. When run they will each be tried in turn
-/// until one succeeds, or they all fail.
-///
-/// ## Examples
-///
-/// > import gleam/result
-/// > let bool_or_string = any(_, of: [
-/// > string,
-/// > fn(x) { result.map(bool(x), fn(_) { "a bool" }) }
-/// > ])
-/// > bool_or_string(from("ok"))
-/// Ok("ok")
-///
-/// > bool_or_string(from(True))
-/// Ok("a bool")
-///
-/// > bool_or_string(from(1))
-/// Error("Unexpected value")
-///
-pub fn any(
- from data: Dynamic,
- of decoders: List(Decoder(t)),
-) -> Result(t, String) {
- decoders
- |> list.find_map(fn(decoder) { decoder(data) })
- |> result.map_error(fn(_) { "Unexpected value" })
+ /// Checks to see if the Dynamic value is map.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/map
+ /// > map(from(map.new()))
+ /// Ok(map.new())
+ ///
+ /// > map(from(1))
+ /// Error("Expected a 2 element tuple, got an int")
+ ///
+ /// > map(from(""))
+ /// Error("Expected a map, got a binary")
+ ///
+ pub external fn map(from: Dynamic) -> Result(Map(Dynamic, Dynamic), String) =
+ "gleam_stdlib" "decode_map"
+
+ /// Joins multiple decoders into one. When run they will each be tried in turn
+ /// until one succeeds, or they all fail.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/result
+ /// > let bool_or_string = any(_, of: [
+ /// > string,
+ /// > fn(x) { result.map(bool(x), fn(_) { "a bool" }) }
+ /// > ])
+ /// > bool_or_string(from("ok"))
+ /// Ok("ok")
+ ///
+ /// > bool_or_string(from(True))
+ /// Ok("a bool")
+ ///
+ /// > bool_or_string(from(1))
+ /// Error("Unexpected value")
+ ///
+ pub fn any(
+ from data: Dynamic,
+ of decoders: List(Decoder(t)),
+ ) -> Result(t, String) {
+ decoders
+ |> list.find_map(fn(decoder) { decoder(data) })
+ |> result.map_error(fn(_) { "Unexpected value" })
+ }
}
diff --git a/src/gleam/float.gleam b/src/gleam/float.gleam
index 2a646c2..ed1d3ab 100644
--- a/src/gleam/float.gleam
+++ b/src/gleam/float.gleam
@@ -1,228 +1,230 @@
-import gleam/string_builder
-import gleam/order.{Order}
-
-pub type Float =
- Float
-
-/// Attempts to parse a string as a float, returning `Error(Nil)` if it was not
-/// possible.
-///
-/// ## Examples
-/// > parse("2.3")
-/// Ok(2.3)
-///
-/// > parse("ABC")
-/// Error(Nil)
-///
-pub external fn parse(String) -> Result(Float, Nil) =
- "gleam_stdlib" "parse_float"
-
-/// Returns the string representation of the provided float.
-///
-/// ## Examples
-/// > to_string(2.3)
-/// "2.3"
-///
-pub fn to_string(f: Float) -> String {
- f
- |> string_builder.from_float
- |> string_builder.to_string
-}
+if erlang {
+ import gleam/string_builder
+ import gleam/order.{Order}
+
+ pub type Float =
+ Float
+
+ /// Attempts to parse a string as a float, returning `Error(Nil)` if it was not
+ /// possible.
+ ///
+ /// ## Examples
+ /// > parse("2.3")
+ /// Ok(2.3)
+ ///
+ /// > parse("ABC")
+ /// Error(Nil)
+ ///
+ pub external fn parse(String) -> Result(Float, Nil) =
+ "gleam_stdlib" "parse_float"
+
+ /// Returns the string representation of the provided float.
+ ///
+ /// ## Examples
+ /// > to_string(2.3)
+ /// "2.3"
+ ///
+ pub fn to_string(f: Float) -> String {
+ f
+ |> string_builder.from_float
+ |> string_builder.to_string
+ }
-/// Restricts a Float between a lower and upper bound
-///
-/// ## Examples
-///
-/// ```
-/// > clamp(1.2, min: 1.4, max: 1.6)
-/// 1.4
-/// ```
-///
-pub fn clamp(n: Float, min min_bound: Float, max max_bound: Float) -> Float {
- n
- |> min(max_bound)
- |> max(min_bound)
-}
+ /// Restricts a Float between a lower and upper bound
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > clamp(1.2, min: 1.4, max: 1.6)
+ /// 1.4
+ /// ```
+ ///
+ pub fn clamp(n: Float, min min_bound: Float, max max_bound: Float) -> Float {
+ n
+ |> min(max_bound)
+ |> max(min_bound)
+ }
-/// Compares two floats, returning an order.
-///
-/// ## Examples
-/// > compare(2.0, 2.3)
-/// Lt
-///
-pub fn compare(a: Float, with b: Float) -> Order {
- case a == b {
- True -> order.Eq
- False ->
- case a <. b {
- True -> order.Lt
- False -> order.Gt
- }
+ /// Compares two floats, returning an order.
+ ///
+ /// ## Examples
+ /// > compare(2.0, 2.3)
+ /// Lt
+ ///
+ pub fn compare(a: Float, with b: Float) -> Order {
+ case a == b {
+ True -> order.Eq
+ False ->
+ case a <. b {
+ True -> order.Lt
+ False -> order.Gt
+ }
+ }
}
-}
-/// Compares two floats, returning the smaller of the two.
-///
-/// ## Examples
-///
-/// > min(2.0, 2.3)
-/// 2.0
-///
-pub fn min(a: Float, b: Float) -> Float {
- case a <. b {
- True -> a
- False -> b
+ /// Compares two floats, returning the smaller of the two.
+ ///
+ /// ## Examples
+ ///
+ /// > min(2.0, 2.3)
+ /// 2.0
+ ///
+ pub fn min(a: Float, b: Float) -> Float {
+ case a <. b {
+ True -> a
+ False -> b
+ }
}
-}
-/// Compares two floats, returning the larger of the two.
-///
-/// ## Examples
-///
-/// > max(2.0, 2.3)
-/// 2.3
-///
-pub fn max(a: Float, b: Float) -> Float {
- case a >. b {
- True -> a
- False -> b
+ /// Compares two floats, returning the larger of the two.
+ ///
+ /// ## Examples
+ ///
+ /// > max(2.0, 2.3)
+ /// 2.3
+ ///
+ pub fn max(a: Float, b: Float) -> Float {
+ case a >. b {
+ True -> a
+ False -> b
+ }
}
-}
-/// Rounds the value to the next highest whole number as a float.
-///
-/// ## Examples
-///
-/// > ceiling(2.3)
-/// 3.0
-///
-pub external fn ceiling(Float) -> Float =
- "math" "ceil"
-
-/// Rounds the value to the next lowest whole number as a float.
-///
-/// ## Examples
-///
-/// > floor(2.3)
-/// 2.0
-///
-pub external fn floor(Float) -> Float =
- "math" "floor"
-
-/// Rounds the value to the nearest whole number as an int.
-///
-/// ## Examples
-///
-/// > round(2.3)
-/// 2
-///
-/// > round(2.5)
-/// 3
-///
-pub external fn round(Float) -> Int =
- "erlang" "round"
-
-/// Returns the value as an int, truncating all decimal digits.
-///
-/// ## Examples
-///
-/// > truncate(2.4343434847383438)
-/// 2
-///
-pub external fn truncate(Float) -> Int =
- "erlang" "trunc"
-
-/// Returns the absolute value of the input as a float.
-///
-/// ## Examples
-///
-/// > absolute_value(-12.5)
-/// 12.5
-///
-/// > absolute_value(10.2)
-/// 10.2
-///
-pub external fn absolute_value(Float) -> Float =
- "erlang" "abs"
-
-/// Returns the results of the base being raised to the power of the
-/// exponent, as a float.
-///
-/// ## Examples
-///
-/// > power(2.0, 2.0)
-/// 4.0
-///
-/// > power(8.0, 1.5)
-/// 64.0
-///
-pub external fn power(base: Float, exponent: Float) -> Float =
- "math" "pow"
-
-/// Returns the square root of the input as a float.
-///
-/// ## Examples
-///
-/// > square_root(4.0)
-/// Ok(2.0)
-///
-/// > square_root(-16.0)
-/// Error(Nil)
-///
-pub fn square_root(number: Float) -> Result(Float, Nil) {
- case number <. 0.0 {
- True -> Error(Nil)
- False -> Ok(power(number, 0.5))
+ /// Rounds the value to the next highest whole number as a float.
+ ///
+ /// ## Examples
+ ///
+ /// > ceiling(2.3)
+ /// 3.0
+ ///
+ pub external fn ceiling(Float) -> Float =
+ "math" "ceil"
+
+ /// Rounds the value to the next lowest whole number as a float.
+ ///
+ /// ## Examples
+ ///
+ /// > floor(2.3)
+ /// 2.0
+ ///
+ pub external fn floor(Float) -> Float =
+ "math" "floor"
+
+ /// Rounds the value to the nearest whole number as an int.
+ ///
+ /// ## Examples
+ ///
+ /// > round(2.3)
+ /// 2
+ ///
+ /// > round(2.5)
+ /// 3
+ ///
+ pub external fn round(Float) -> Int =
+ "erlang" "round"
+
+ /// Returns the value as an int, truncating all decimal digits.
+ ///
+ /// ## Examples
+ ///
+ /// > truncate(2.4343434847383438)
+ /// 2
+ ///
+ pub external fn truncate(Float) -> Int =
+ "erlang" "trunc"
+
+ /// Returns the absolute value of the input as a float.
+ ///
+ /// ## Examples
+ ///
+ /// > absolute_value(-12.5)
+ /// 12.5
+ ///
+ /// > absolute_value(10.2)
+ /// 10.2
+ ///
+ pub external fn absolute_value(Float) -> Float =
+ "erlang" "abs"
+
+ /// Returns the results of the base being raised to the power of the
+ /// exponent, as a float.
+ ///
+ /// ## Examples
+ ///
+ /// > power(2.0, 2.0)
+ /// 4.0
+ ///
+ /// > power(8.0, 1.5)
+ /// 64.0
+ ///
+ pub external fn power(base: Float, exponent: Float) -> Float =
+ "math" "pow"
+
+ /// Returns the square root of the input as a float.
+ ///
+ /// ## Examples
+ ///
+ /// > square_root(4.0)
+ /// Ok(2.0)
+ ///
+ /// > square_root(-16.0)
+ /// Error(Nil)
+ ///
+ pub fn square_root(number: Float) -> Result(Float, Nil) {
+ case number <. 0.0 {
+ True -> Error(Nil)
+ False -> Ok(power(number, 0.5))
+ }
}
-}
-/// Returns the negative of the value provided
-///
-/// ## Examples
-///
-/// > negate(1.)
-/// -1.
-///
-pub fn negate(x: Float) -> Float {
- -1. *. x
-}
+ /// Returns the negative of the value provided
+ ///
+ /// ## Examples
+ ///
+ /// > negate(1.)
+ /// -1.
+ ///
+ pub fn negate(x: Float) -> Float {
+ -1. *. x
+ }
-/// Sums a list of Floats.
-///
-/// ## Example
-///
-/// > sum([1.0, 2.2, 3.3])
-/// 6.5
-///
-pub fn sum(numbers: List(Float)) -> Float {
- numbers
- |> do_sum(0.0)
-}
+ /// Sums a list of Floats.
+ ///
+ /// ## Example
+ ///
+ /// > sum([1.0, 2.2, 3.3])
+ /// 6.5
+ ///
+ pub fn sum(numbers: List(Float)) -> Float {
+ numbers
+ |> do_sum(0.0)
+ }
-fn do_sum(numbers: List(Float), initial: Float) -> Float {
- case numbers {
- [] -> initial
- [x, ..rest] -> do_sum(rest, x +. initial)
+ fn do_sum(numbers: List(Float), initial: Float) -> Float {
+ case numbers {
+ [] -> initial
+ [x, ..rest] -> do_sum(rest, x +. initial)
+ }
}
-}
-/// Multiplies a list of Floats and returns the product.
-///
-/// ## Example
-///
-/// > product([2.5, 3.2, 4.2])
-/// 33.6
-///
-pub fn product(numbers: List(Float)) -> Float {
- case numbers {
- [] -> 0.
- _ -> do_product(numbers, 1.)
+ /// Multiplies a list of Floats and returns the product.
+ ///
+ /// ## Example
+ ///
+ /// > product([2.5, 3.2, 4.2])
+ /// 33.6
+ ///
+ pub fn product(numbers: List(Float)) -> Float {
+ case numbers {
+ [] -> 0.
+ _ -> do_product(numbers, 1.)
+ }
}
-}
-fn do_product(numbers: List(Float), initial: Float) -> Float {
- case numbers {
- [] -> initial
- [x, ..rest] -> do_product(rest, x *. initial)
+ fn do_product(numbers: List(Float), initial: Float) -> Float {
+ case numbers {
+ [] -> initial
+ [x, ..rest] -> do_product(rest, x *. initial)
+ }
}
}
diff --git a/src/gleam/function.gleam b/src/gleam/function.gleam
index 08e7efd..937a9bc 100644
--- a/src/gleam/function.gleam
+++ b/src/gleam/function.gleam
@@ -1,71 +1,73 @@
-import gleam/dynamic.{Dynamic}
+if erlang {
+ import gleam/dynamic.{Dynamic}
-/// Takes two functions and chains them together to form one function that takes
-/// the input from the first and returns the output of the second.
-///
-pub fn compose(fun1: fn(a) -> b, fun2: fn(b) -> c) -> fn(a) -> c {
- fn(a) { fun2(fun1(a)) }
-}
+ /// Takes two functions and chains them together to form one function that takes
+ /// the input from the first and returns the output of the second.
+ ///
+ pub fn compose(fun1: fn(a) -> b, fun2: fn(b) -> c) -> fn(a) -> c {
+ fn(a) { fun2(fun1(a)) }
+ }
-/// Takes a function with arity two
-/// and returns a curried equivalent.
-/// fn(a, b) -> c becomes fn(a) -> fn(b) -> c
-pub fn curry2(fun: fn(a, b) -> value) {
- fn(a) { fn(b) { fun(a, b) } }
-}
+ /// Takes a function with arity two
+ /// and returns a curried equivalent.
+ /// fn(a, b) -> c becomes fn(a) -> fn(b) -> c
+ pub fn curry2(fun: fn(a, b) -> value) {
+ fn(a) { fn(b) { fun(a, b) } }
+ }
-/// Takes a function with arity three
-/// and returns a curried equivalent.
-/// fn(a, b, c) -> d becomes fn(a) -> fn(b) -> fn(c) -> d
-pub fn curry3(fun: fn(a, b, c) -> value) {
- fn(a) { fn(b) { fn(c) { fun(a, b, c) } } }
-}
+ /// Takes a function with arity three
+ /// and returns a curried equivalent.
+ /// fn(a, b, c) -> d becomes fn(a) -> fn(b) -> fn(c) -> d
+ pub fn curry3(fun: fn(a, b, c) -> value) {
+ fn(a) { fn(b) { fn(c) { fun(a, b, c) } } }
+ }
-/// Takes a function with arity four
-/// and returns a curried equivalent.
-pub fn curry4(fun: fn(a, b, c, d) -> value) {
- fn(a) { fn(b) { fn(c) { fn(d) { fun(a, b, c, d) } } } }
-}
+ /// Takes a function with arity four
+ /// and returns a curried equivalent.
+ pub fn curry4(fun: fn(a, b, c, d) -> value) {
+ fn(a) { fn(b) { fn(c) { fn(d) { fun(a, b, c, d) } } } }
+ }
-/// Takes a function with arity five
-/// and returns a curried equivalent.
-pub fn curry5(fun: fn(a, b, c, d, e) -> value) {
- fn(a) { fn(b) { fn(c) { fn(d) { fn(e) { fun(a, b, c, d, e) } } } } }
-}
+ /// Takes a function with arity five
+ /// and returns a curried equivalent.
+ pub fn curry5(fun: fn(a, b, c, d, e) -> value) {
+ fn(a) { fn(b) { fn(c) { fn(d) { fn(e) { fun(a, b, c, d, e) } } } } }
+ }
-/// Takes a function with arity six
-/// and returns a curried equivalent.
-pub fn curry6(fun: fn(a, b, c, d, e, f) -> value) {
- fn(a) {
- fn(b) { fn(c) { fn(d) { fn(e) { fn(f) { fun(a, b, c, d, e, f) } } } } }
+ /// Takes a function with arity six
+ /// and returns a curried equivalent.
+ pub fn curry6(fun: fn(a, b, c, d, e, f) -> value) {
+ fn(a) {
+ fn(b) { fn(c) { fn(d) { fn(e) { fn(f) { fun(a, b, c, d, e, f) } } } } }
+ }
}
-}
-/// Takes a function that takes two arguments and returns a new function that
-/// takes the same two arguments, but in reverse order.
-///
-pub fn flip(fun: fn(a, b) -> c) -> fn(b, a) -> c {
- fn(b, a) { fun(a, b) }
-}
+ /// Takes a function that takes two arguments and returns a new function that
+ /// takes the same two arguments, but in reverse order.
+ ///
+ pub fn flip(fun: fn(a, b) -> c) -> fn(b, a) -> c {
+ fn(b, a) { fun(a, b) }
+ }
-/// A function that always returns its input value.
-///
-pub fn identity(x: a) -> a {
- x
-}
+ /// A function that always returns its input value.
+ ///
+ pub fn identity(x: a) -> a {
+ x
+ }
-pub type Exception {
- Exited(Dynamic)
- Thrown(Dynamic)
- Errored(Dynamic)
-}
+ pub type Exception {
+ Exited(Dynamic)
+ Thrown(Dynamic)
+ Errored(Dynamic)
+ }
-/// Gleam doesn't offer any way to raise exceptions, but they may still occur
-/// due to bugs when working with unsafe code, such as when calling Erlang
-/// function.
-///
-/// This function will catch any error thrown and convert it into a result
-/// rather than crashing the process.
-///
-pub external fn rescue(fn() -> a) -> Result(a, Exception) =
- "gleam_stdlib" "rescue"
+ /// Gleam doesn't offer any way to raise exceptions, but they may still occur
+ /// due to bugs when working with unsafe code, such as when calling Erlang
+ /// function.
+ ///
+ /// This function will catch any error thrown and convert it into a result
+ /// rather than crashing the process.
+ ///
+ pub external fn rescue(fn() -> a) -> Result(a, Exception) =
+ "gleam_stdlib" "rescue"
+}
diff --git a/src/gleam/int.gleam b/src/gleam/int.gleam
index b77500c..b65d3a3 100644
--- a/src/gleam/int.gleam
+++ b/src/gleam/int.gleam
@@ -1,222 +1,224 @@
-import gleam/order.{Order}
-
-pub type Int =
- Int
-
-/// Returns the absolute value of the input.
-///
-/// ## Examples
-///
-/// > absolute_value(-12)
-/// 12
-///
-/// > absolute_value(10)
-/// 10
-///
-pub fn absolute_value(num: Int) -> Int {
- case num >= 0 {
- True -> num
- False -> num * -1
+if erlang {
+ import gleam/order.{Order}
+
+ pub type Int =
+ Int
+
+ /// Returns the absolute value of the input.
+ ///
+ /// ## Examples
+ ///
+ /// > absolute_value(-12)
+ /// 12
+ ///
+ /// > absolute_value(10)
+ /// 10
+ ///
+ pub fn absolute_value(num: Int) -> Int {
+ case num >= 0 {
+ True -> num
+ False -> num * -1
+ }
}
-}
-/// Parses a given string as an int if possible.
-///
-/// ## Examples
-///
-/// > parse("2")
-/// Ok(2)
-///
-/// > parse("ABC")
-/// Error(Nil)
-///
-pub external fn parse(String) -> Result(Int, Nil) =
- "gleam_stdlib" "parse_int"
-
-/// Prints a given int to a string.
-///
-/// ## Examples
-///
-/// > to_string(2)
-/// "2"
-///
-pub external fn to_string(Int) -> String =
- "erlang" "integer_to_binary"
-
-/// Prints a given int to a string using the base number provided.
-///
-/// ## Examples
-///
-/// > to_base_string(2, 2)
-/// "10"
-///
-/// > to_base_string(48, 16)
-/// "30"
-///
-/// > to_base_string(48, 36)
-/// "1C"
-///
-pub external fn to_base_string(Int, Int) -> String =
- "erlang" "integer_to_binary"
-
-/// Takes an int and returns its value as a float
-///
-/// ## Examples
-///
-/// > to_float(5)
-/// 5.
-///
-/// > to_float(0)
-/// 0.
-///
-/// > to_float(-3)
-/// -3.
-///
-pub external fn to_float(a: Int) -> Float =
- "erlang" "float"
-
-/// Restricts an Int between a lower and upper bound
-///
-/// ## Examples
-///
-/// ```
-/// > clamp(40, min: 50, max: 60)
-/// 50
-/// ```
-///
-pub fn clamp(n: Int, min min_bound: Int, max max_bound: Int) -> Int {
- n
- |> min(max_bound)
- |> max(min_bound)
-}
+ /// Parses a given string as an int if possible.
+ ///
+ /// ## Examples
+ ///
+ /// > parse("2")
+ /// Ok(2)
+ ///
+ /// > parse("ABC")
+ /// Error(Nil)
+ ///
+ pub external fn parse(String) -> Result(Int, Nil) =
+ "gleam_stdlib" "parse_int"
+
+ /// Prints a given int to a string.
+ ///
+ /// ## Examples
+ ///
+ /// > to_string(2)
+ /// "2"
+ ///
+ pub external fn to_string(Int) -> String =
+ "erlang" "integer_to_binary"
+
+ /// Prints a given int to a string using the base number provided.
+ ///
+ /// ## Examples
+ ///
+ /// > to_base_string(2, 2)
+ /// "10"
+ ///
+ /// > to_base_string(48, 16)
+ /// "30"
+ ///
+ /// > to_base_string(48, 36)
+ /// "1C"
+ ///
+ pub external fn to_base_string(Int, Int) -> String =
+ "erlang" "integer_to_binary"
+
+ /// Takes an int and returns its value as a float
+ ///
+ /// ## Examples
+ ///
+ /// > to_float(5)
+ /// 5.
+ ///
+ /// > to_float(0)
+ /// 0.
+ ///
+ /// > to_float(-3)
+ /// -3.
+ ///
+ pub external fn to_float(a: Int) -> Float =
+ "erlang" "float"
+
+ /// Restricts an Int between a lower and upper bound
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > clamp(40, min: 50, max: 60)
+ /// 50
+ /// ```
+ ///
+ pub fn clamp(n: Int, min min_bound: Int, max max_bound: Int) -> Int {
+ n
+ |> min(max_bound)
+ |> max(min_bound)
+ }
-/// Compares two ints, returning an order.
-///
-/// ## Examples
-///
-/// > compare(2, 3)
-/// Lt
-///
-/// > compare(4, 3)
-/// Gt
-///
-/// > compare(3, 3)
-/// Eq
-///
-pub fn compare(a: Int, with b: Int) -> Order {
- case a == b {
- True -> order.Eq
- False ->
- case a < b {
- True -> order.Lt
- False -> order.Gt
- }
+ /// Compares two ints, returning an order.
+ ///
+ /// ## Examples
+ ///
+ /// > compare(2, 3)
+ /// Lt
+ ///
+ /// > compare(4, 3)
+ /// Gt
+ ///
+ /// > compare(3, 3)
+ /// Eq
+ ///
+ pub fn compare(a: Int, with b: Int) -> Order {
+ case a == b {
+ True -> order.Eq
+ False ->
+ case a < b {
+ True -> order.Lt
+ False -> order.Gt
+ }
+ }
}
-}
-/// Compares two int, returning the smaller of the two.
-///
-/// ## Examples
-///
-/// > min(2, 3)
-/// 2
-///
-pub fn min(a: Int, b: Int) -> Int {
- case a < b {
- True -> a
- False -> b
+ /// Compares two int, returning the smaller of the two.
+ ///
+ /// ## Examples
+ ///
+ /// > min(2, 3)
+ /// 2
+ ///
+ pub fn min(a: Int, b: Int) -> Int {
+ case a < b {
+ True -> a
+ False -> b
+ }
}
-}
-/// Compares two int, returning the larger of the two.
-///
-/// ## Examples
-///
-/// > max(2, 3)
-/// 3
-///
-pub fn max(a: Int, b: Int) -> Int {
- case a > b {
- True -> a
- False -> b
+ /// Compares two int, returning the larger of the two.
+ ///
+ /// ## Examples
+ ///
+ /// > max(2, 3)
+ /// 3
+ ///
+ pub fn max(a: Int, b: Int) -> Int {
+ case a > b {
+ True -> a
+ False -> b
+ }
}
-}
-/// Returns whether the value provided is even.
-///
-/// ## Examples
-///
-/// > is_even(2)
-/// True
-///
-/// > is_even(3)
-/// False
-///
-pub fn is_even(x: Int) -> Bool {
- x % 2 == 0
-}
+ /// Returns whether the value provided is even.
+ ///
+ /// ## Examples
+ ///
+ /// > is_even(2)
+ /// True
+ ///
+ /// > is_even(3)
+ /// False
+ ///
+ pub fn is_even(x: Int) -> Bool {
+ x % 2 == 0
+ }
-/// Returns whether the value provided is odd.
-///
-/// ## Examples
-///
-/// > is_odd(3)
-/// True
-///
-/// > is_odd(2)
-/// False
-///
-pub fn is_odd(x: Int) -> Bool {
- x % 2 != 0
-}
+ /// Returns whether the value provided is odd.
+ ///
+ /// ## Examples
+ ///
+ /// > is_odd(3)
+ /// True
+ ///
+ /// > is_odd(2)
+ /// False
+ ///
+ pub fn is_odd(x: Int) -> Bool {
+ x % 2 != 0
+ }
-/// Returns the negative of the value provided
-///
-/// ## Examples
-///
-/// > negate(1)
-/// -1
-///
-pub fn negate(x: Int) -> Int {
- -1 * x
-}
+ /// Returns the negative of the value provided
+ ///
+ /// ## Examples
+ ///
+ /// > negate(1)
+ /// -1
+ ///
+ pub fn negate(x: Int) -> Int {
+ -1 * x
+ }
-/// Sums a list of Ints.
-///
-/// ## Example
-///
-/// > sum([1, 2, 3])
-/// 6
-///
-pub fn sum(numbers: List(Int)) -> Int {
- numbers
- |> do_sum(0)
-}
+ /// Sums a list of Ints.
+ ///
+ /// ## Example
+ ///
+ /// > sum([1, 2, 3])
+ /// 6
+ ///
+ pub fn sum(numbers: List(Int)) -> Int {
+ numbers
+ |> do_sum(0)
+ }
-fn do_sum(numbers: List(Int), initial: Int) -> Int {
- case numbers {
- [] -> initial
- [x, ..rest] -> do_sum(rest, x + initial)
+ fn do_sum(numbers: List(Int), initial: Int) -> Int {
+ case numbers {
+ [] -> initial
+ [x, ..rest] -> do_sum(rest, x + initial)
+ }
}
-}
-/// Multiplies a list of Ints and returns the product.
-///
-/// ## Example
-///
-/// > product([2, 3, 4])
-/// 24
-///
-pub fn product(numbers: List(Int)) -> Int {
- case numbers {
- [] -> 0
- _ -> do_product(numbers, 1)
+ /// Multiplies a list of Ints and returns the product.
+ ///
+ /// ## Example
+ ///
+ /// > product([2, 3, 4])
+ /// 24
+ ///
+ pub fn product(numbers: List(Int)) -> Int {
+ case numbers {
+ [] -> 0
+ _ -> do_product(numbers, 1)
+ }
}
-}
-fn do_product(numbers: List(Int), initial: Int) -> Int {
- case numbers {
- [] -> initial
- [x, ..rest] -> do_product(rest, x * initial)
+ fn do_product(numbers: List(Int), initial: Int) -> Int {
+ case numbers {
+ [] -> initial
+ [x, ..rest] -> do_product(rest, x * initial)
+ }
}
}
diff --git a/src/gleam/io.gleam b/src/gleam/io.gleam
index a5b37df..f6e7f40 100644
--- a/src/gleam/io.gleam
+++ b/src/gleam/io.gleam
@@ -1,75 +1,77 @@
-external type DoNotLeak
+if erlang {
+ external type DoNotLeak
-external fn erl_print(String, List(a)) -> DoNotLeak =
- "io" "fwrite"
+ external fn erl_print(String, List(a)) -> DoNotLeak =
+ "io" "fwrite"
-/// Writes a string to standard output.
-///
-/// ## Example
-///
-/// > io.print("Hi mum")
-/// // -> Hi mum
-/// Nil
-///
-pub fn print(string: String) -> Nil {
- erl_print(string, [])
- Nil
-}
+ /// Writes a string to standard output.
+ ///
+ /// ## Example
+ ///
+ /// > io.print("Hi mum")
+ /// // -> Hi mum
+ /// Nil
+ ///
+ pub fn print(string: String) -> Nil {
+ erl_print(string, [])
+ Nil
+ }
-/// Writes a string to standard output, appending a newline to the end.
-///
-/// ## Example
-///
-/// > io.println("Hi mum")
-/// // -> Hi mum
-/// Nil
-///
-pub fn println(string: String) -> Nil {
- erl_print("~ts\n", [string])
- Nil
-}
+ /// Writes a string to standard output, appending a newline to the end.
+ ///
+ /// ## Example
+ ///
+ /// > io.println("Hi mum")
+ /// // -> Hi mum
+ /// Nil
+ ///
+ pub fn println(string: String) -> Nil {
+ erl_print("~ts\n", [string])
+ Nil
+ }
-/// Prints a value to standard output using Erlang syntax.
-///
-/// The value is returned after being printed so it can be used in pipelines.
-///
-/// ## Example
-///
-/// > io.debug("Hi mum")
-/// // -> <<"Hi mum">>
-/// "Hi mum"
-///
-/// > io.debug(Ok(1))
-/// // -> {ok, 1}
-/// Ok(1)
-///
-/// > import list
-/// > [1, 2]
-/// > |> list.map(fn(x) { x + 1 })
-/// > |> io.debug
-/// > |> list.map(fn(x) { x * 2 })
-/// // -> [2, 3]
-/// [4, 6]
-///
-pub fn debug(term: anything) -> anything {
- erl_print("~tp\n", [term])
- term
-}
+ /// Prints a value to standard output using Erlang syntax.
+ ///
+ /// The value is returned after being printed so it can be used in pipelines.
+ ///
+ /// ## Example
+ ///
+ /// > io.debug("Hi mum")
+ /// // -> <<"Hi mum">>
+ /// "Hi mum"
+ ///
+ /// > io.debug(Ok(1))
+ /// // -> {ok, 1}
+ /// Ok(1)
+ ///
+ /// > import list
+ /// > [1, 2]
+ /// > |> list.map(fn(x) { x + 1 })
+ /// > |> io.debug
+ /// > |> list.map(fn(x) { x * 2 })
+ /// // -> [2, 3]
+ /// [4, 6]
+ ///
+ pub fn debug(term: anything) -> anything {
+ erl_print("~tp\n", [term])
+ term
+ }
-/// Error value returned by `get_line` function
-///
-pub type GetLineError {
- Eof
- NoData
-}
+ /// Error value returned by `get_line` function
+ ///
+ pub type GetLineError {
+ Eof
+ NoData
+ }
-/// Reads a line from standard input with the given prompt.
-///
-/// # Example
-///
-/// > io.get_line("Language: ")
-/// // -> Language: <- gleam
-/// Ok("gleam\n")
-///
-pub external fn get_line(prompt: String) -> Result(String, GetLineError) =
- "gleam_stdlib" "get_line"
+ /// Reads a line from standard input with the given prompt.
+ ///
+ /// # Example
+ ///
+ /// > io.get_line("Language: ")
+ /// // -> Language: <- gleam
+ /// Ok("gleam\n")
+ ///
+ pub external fn get_line(prompt: String) -> Result(String, GetLineError) =
+ "gleam_stdlib" "get_line"
+}
diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam
index 1b347c4..ff2e020 100644
--- a/src/gleam/iterator.gleam
+++ b/src/gleam/iterator.gleam
@@ -1,1029 +1,1037 @@
-import gleam/list
-import gleam/map.{Map}
-
-// Internal private representation of an Iterator
-type Action(element) {
- Stop
- Continue(element, fn() -> Action(element))
-}
+if erlang {
+ import gleam/list
+ import gleam/map.{Map}
+
+ // Internal private representation of an Iterator
+ type Action(element) {
+ Stop
+ Continue(element, fn() -> Action(element))
+ }
-/// An iterator is a lazily evaluated sequence of element.
-///
-/// Iterators are useful when working with collections that are too large to
-/// fit in memory (or those that are infinite in size) as they only require the
-/// elements currently being processed to be in memory.
-///
-/// As a lazy data structure no work is done when an iterator is filters,
-/// mapped, etc, instead a new iterator is returned with these transformations
-/// applied to the stream. Once the stream has all the required transformations
-/// applied it can be evaluated using functions such as `fold` and `to_list`.
-///
-pub opaque type Iterator(element) {
- Iterator(continuation: fn() -> Action(element))
-}
+ /// An iterator is a lazily evaluated sequence of element.
+ ///
+ /// Iterators are useful when working with collections that are too large to
+ /// fit in memory (or those that are infinite in size) as they only require the
+ /// elements currently being processed to be in memory.
+ ///
+ /// As a lazy data structure no work is done when an iterator is filters,
+ /// mapped, etc, instead a new iterator is returned with these transformations
+ /// applied to the stream. Once the stream has all the required transformations
+ /// applied it can be evaluated using functions such as `fold` and `to_list`.
+ ///
+ pub opaque type Iterator(element) {
+ Iterator(continuation: fn() -> Action(element))
+ }
-// Public API for iteration
-pub type Step(element, accumulator) {
- Next(element: element, accumulator: accumulator)
- Done
-}
+ // Public API for iteration
+ pub type Step(element, accumulator) {
+ Next(element: element, accumulator: accumulator)
+ Done
+ }
-// Shortcut for an empty iterator.
-fn stop() -> Action(element) {
- Stop
-}
+ // Shortcut for an empty iterator.
+ fn stop() -> Action(element) {
+ Stop
+ }
-// Creating Iterators
-fn do_unfold(
- initial: acc,
- f: fn(acc) -> Step(element, acc),
-) -> fn() -> Action(element) {
- fn() {
- case f(initial) {
- Next(x, acc) -> Continue(x, do_unfold(acc, f))
- Done -> Stop
+ // Creating Iterators
+ fn do_unfold(
+ initial: acc,
+ f: fn(acc) -> Step(element, acc),
+ ) -> fn() -> Action(element) {
+ fn() {
+ case f(initial) {
+ Next(x, acc) -> Continue(x, do_unfold(acc, f))
+ Done -> Stop
+ }
}
}
-}
-/// Creates an iterator from a given function and accumulator.
-///
-/// The function is called on the accumulator and returns either `Done`,
-/// indicating the iterator has no more elements, or `Next` which contains a
-/// new element and accumulator. The element is yielded by the iterator and the
-/// new accumulator is used with the function to compute the next element in
-/// the sequence.
-///
-/// ## Examples
-///
-/// > unfold(from: 5, with: fn(n) {
-/// > case n {
-/// > 0 -> Done
-/// > n -> Next(element: n, accumulator: n - 1)
-/// > }
-/// > })
-/// > |> to_list
-/// [5, 4, 3, 2, 1]
-///
-pub fn unfold(
- from initial: acc,
- with f: fn(acc) -> Step(element, acc),
-) -> Iterator(element) {
- initial
- |> do_unfold(f)
- |> Iterator
-}
+ /// Creates an iterator from a given function and accumulator.
+ ///
+ /// The function is called on the accumulator and returns either `Done`,
+ /// indicating the iterator has no more elements, or `Next` which contains a
+ /// new element and accumulator. The element is yielded by the iterator and the
+ /// new accumulator is used with the function to compute the next element in
+ /// the sequence.
+ ///
+ /// ## Examples
+ ///
+ /// > unfold(from: 5, with: fn(n) {
+ /// > case n {
+ /// > 0 -> Done
+ /// > n -> Next(element: n, accumulator: n - 1)
+ /// > }
+ /// > })
+ /// > |> to_list
+ /// [5, 4, 3, 2, 1]
+ ///
+ pub fn unfold(
+ from initial: acc,
+ with f: fn(acc) -> Step(element, acc),
+ ) -> Iterator(element) {
+ initial
+ |> do_unfold(f)
+ |> Iterator
+ }
-// TODO: test
-/// Creates an iterator that yields values created by calling a given function
-/// repeatedly.
-///
-pub fn repeatedly(f: fn() -> element) -> Iterator(element) {
- unfold(Nil, fn(_) { Next(f(), Nil) })
-}
+ // TODO: test
+ /// Creates an iterator that yields values created by calling a given function
+ /// repeatedly.
+ ///
+ pub fn repeatedly(f: fn() -> element) -> Iterator(element) {
+ unfold(Nil, fn(_) { Next(f(), Nil) })
+ }
-/// Creates an iterator that returns the same value infinitely.
-///
-/// ## Examples
-///
-/// > repeat(10)
-/// > |> take(4)
-/// > |> to_list
-/// [10, 10, 10, 10]
-///
-pub fn repeat(x: element) -> Iterator(element) {
- repeatedly(fn() { x })
-}
+ /// Creates an iterator that returns the same value infinitely.
+ ///
+ /// ## Examples
+ ///
+ /// > repeat(10)
+ /// > |> take(4)
+ /// > |> to_list
+ /// [10, 10, 10, 10]
+ ///
+ pub fn repeat(x: element) -> Iterator(element) {
+ repeatedly(fn() { x })
+ }
-/// Creates an iterator that yields each element from the given list.
-///
-/// ## Examples
-///
-/// > from_list([1, 2, 3, 4]) |> to_list
-/// [1, 2, 3, 4]
-///
-pub fn from_list(list: List(element)) -> Iterator(element) {
- let yield = fn(acc) {
- case acc {
- [] -> Done
- [head, ..tail] -> Next(head, tail)
+ /// Creates an iterator that yields each element from the given list.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([1, 2, 3, 4]) |> to_list
+ /// [1, 2, 3, 4]
+ ///
+ pub fn from_list(list: List(element)) -> Iterator(element) {
+ let yield = fn(acc) {
+ case acc {
+ [] -> Done
+ [head, ..tail] -> Next(head, tail)
+ }
}
+ unfold(list, yield)
}
- unfold(list, yield)
-}
-// Consuming Iterators
-fn do_fold(
- continuation: fn() -> Action(e),
- f: fn(e, acc) -> acc,
- accumulator: acc,
-) -> acc {
- case continuation() {
- Continue(elem, next) -> do_fold(next, f, f(elem, accumulator))
- Stop -> accumulator
+ // Consuming Iterators
+ fn do_fold(
+ continuation: fn() -> Action(e),
+ f: fn(e, acc) -> acc,
+ accumulator: acc,
+ ) -> acc {
+ case continuation() {
+ Continue(elem, next) -> do_fold(next, f, f(elem, accumulator))
+ Stop -> accumulator
+ }
}
-}
-/// Reduces an iterator of elements into a single value by calling a given
-/// function on each element in turn.
-///
-/// If called on an iterator of infinite length then this function will never
-/// return.
-///
-/// If you do not care about the end value and only wish to evaluate the
-/// iterator for side effects consider using the `run` function instead.
-///
-/// ## Examples
-///
-/// > [1, 2, 3, 4]
-/// > |> from_list
-/// > |> fold(from: 0, with: fn(element, acc) { element + acc })
-/// 10
-///
-pub fn fold(
- over iterator: Iterator(e),
- from initial: acc,
- with f: fn(e, acc) -> acc,
-) -> acc {
- iterator.continuation
- |> do_fold(f, initial)
-}
-
-// TODO: test
-/// Evaluates all elements emitted by the given iterator. This function is useful for when
-/// you wish to trigger any side effects that would occur when evaluating
-/// the iterator.
-///
-pub fn run(iterator: Iterator(e)) -> Nil {
- fold(iterator, Nil, fn(_, _) { Nil })
-}
+ /// Reduces an iterator of elements into a single value by calling a given
+ /// function on each element in turn.
+ ///
+ /// If called on an iterator of infinite length then this function will never
+ /// return.
+ ///
+ /// If you do not care about the end value and only wish to evaluate the
+ /// iterator for side effects consider using the `run` function instead.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2, 3, 4]
+ /// > |> from_list
+ /// > |> fold(from: 0, with: fn(element, acc) { element + acc })
+ /// 10
+ ///
+ pub fn fold(
+ over iterator: Iterator(e),
+ from initial: acc,
+ with f: fn(e, acc) -> acc,
+ ) -> acc {
+ iterator.continuation
+ |> do_fold(f, initial)
+ }
-/// Evaluates an iterator and returns all the elements as a list.
-///
-/// If called on an iterator of infinite length then this function will never
-/// return.
-///
-/// ## Examples
-///
-/// > [1, 2, 3] |> from_list |> map(fn(x) { x * 2 }) |> to_list
-/// [2, 4, 6]
-///
-pub fn to_list(iterator: Iterator(element)) -> List(element) {
- iterator
- |> fold([], fn(e, acc) { [e, ..acc] })
- |> list.reverse
-}
+ // TODO: test
+ /// Evaluates all elements emitted by the given iterator. This function is useful for when
+ /// you wish to trigger any side effects that would occur when evaluating
+ /// the iterator.
+ ///
+ pub fn run(iterator: Iterator(e)) -> Nil {
+ fold(iterator, Nil, fn(_, _) { Nil })
+ }
-/// Eagerly accesses the first value of an interator, returning a `Next`
-/// that contains the first value and the rest of the iterator.
-///
-/// If called on an empty iterator, `Done` is returned.
-///
-/// ## Examples
-///
-/// > assert Next(head, tail) =
-/// > [1, 2, 3, 4]
-/// > |> from_list
-/// > |> step
-/// > head
-/// 1
-///
-/// > tail |> to_list
-/// [2, 3, 4]
-///
-/// > empty() |> step
-/// Done
-///
-pub fn step(iterator: Iterator(e)) -> Step(e, Iterator(e)) {
- case iterator.continuation() {
- Stop -> Done
- Continue(e, a) -> Next(e, Iterator(a))
+ /// Evaluates an iterator and returns all the elements as a list.
+ ///
+ /// If called on an iterator of infinite length then this function will never
+ /// return.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2, 3] |> from_list |> map(fn(x) { x * 2 }) |> to_list
+ /// [2, 4, 6]
+ ///
+ pub fn to_list(iterator: Iterator(element)) -> List(element) {
+ iterator
+ |> fold([], fn(e, acc) { [e, ..acc] })
+ |> list.reverse
}
-}
-fn do_take(continuation: fn() -> Action(e), desired: Int) -> fn() -> Action(e) {
- fn() {
- case desired > 0 {
- False -> Stop
- True ->
- case continuation() {
- Stop -> Stop
- Continue(e, next) -> Continue(e, do_take(next, desired - 1))
- }
+ /// Eagerly accesses the first value of an interator, returning a `Next`
+ /// that contains the first value and the rest of the iterator.
+ ///
+ /// If called on an empty iterator, `Done` is returned.
+ ///
+ /// ## Examples
+ ///
+ /// > assert Next(head, tail) =
+ /// > [1, 2, 3, 4]
+ /// > |> from_list
+ /// > |> step
+ /// > head
+ /// 1
+ ///
+ /// > tail |> to_list
+ /// [2, 3, 4]
+ ///
+ /// > empty() |> step
+ /// Done
+ ///
+ pub fn step(iterator: Iterator(e)) -> Step(e, Iterator(e)) {
+ case iterator.continuation() {
+ Stop -> Done
+ Continue(e, a) -> Next(e, Iterator(a))
}
}
-}
-
-/// Creates an iterator that only yields the first `desired` elements.
-///
-/// If the iterator does not have enough elements all of them are yielded.
-///
-/// ## Examples
-///
-/// > [1, 2, 3, 4, 5] |> from_list |> take(up_to: 3) |> to_list
-/// [1, 2, 3]
-///
-/// > [1, 2] |> from_list |> take(up_to: 3) |> to_list
-/// [1, 2]
-///
-pub fn take(from iterator: Iterator(e), up_to desired: Int) -> Iterator(e) {
- iterator.continuation
- |> do_take(desired)
- |> Iterator
-}
-fn do_drop(continuation: fn() -> Action(e), desired: Int) -> Action(e) {
- case continuation() {
- Stop -> Stop
- Continue(e, next) ->
+ fn do_take(continuation: fn() -> Action(e), desired: Int) -> fn() -> Action(e) {
+ fn() {
case desired > 0 {
- True -> do_drop(next, desired - 1)
- False -> Continue(e, next)
+ False -> Stop
+ True ->
+ case continuation() {
+ Stop -> Stop
+ Continue(e, next) -> Continue(e, do_take(next, desired - 1))
+ }
}
+ }
}
-}
-/// Evaluates and discards the first N elements in an iterator, returning a new
-/// iterator.
-///
-/// If the iterator does not have enough elements an empty iterator is
-/// returned.
-///
-/// This function does not evaluate the elements of the iterator, the
-/// computation is performed when the iterator is later run.
-///
-/// ## Examples
-///
-/// > [1, 2, 3, 4, 5] |> from_list |> drop(up_to: 3) |> to_list
-/// [4, 5]
-///
-/// > [1, 2] |> from_list |> drop(up_to: 3) |> to_list
-/// []
-///
-pub fn drop(from iterator: Iterator(e), up_to desired: Int) -> Iterator(e) {
- fn() { do_drop(iterator.continuation, desired) }
- |> Iterator
-}
+ /// Creates an iterator that only yields the first `desired` elements.
+ ///
+ /// If the iterator does not have enough elements all of them are yielded.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2, 3, 4, 5] |> from_list |> take(up_to: 3) |> to_list
+ /// [1, 2, 3]
+ ///
+ /// > [1, 2] |> from_list |> take(up_to: 3) |> to_list
+ /// [1, 2]
+ ///
+ pub fn take(from iterator: Iterator(e), up_to desired: Int) -> Iterator(e) {
+ iterator.continuation
+ |> do_take(desired)
+ |> Iterator
+ }
-fn do_map(continuation: fn() -> Action(a), f: fn(a) -> b) -> fn() -> Action(b) {
- fn() {
+ fn do_drop(continuation: fn() -> Action(e), desired: Int) -> Action(e) {
case continuation() {
Stop -> Stop
- Continue(e, continuation) -> Continue(f(e), do_map(continuation, f))
+ Continue(e, next) ->
+ case desired > 0 {
+ True -> do_drop(next, desired - 1)
+ False -> Continue(e, next)
+ }
}
}
-}
-/// Creates an iterator from an existing iterator and a transformation function.
-///
-/// Each element in the new iterator will be the result of calling the given
-/// function on the elements in the given iterator.
-///
-/// This function does not evaluate the elements of the iterator, the
-/// computation is performed when the iterator is later run.
-///
-/// ## Examples
-///
-/// > [1, 2, 3] |> from_list |> map(fn(x) { x * 2 }) |> to_list
-/// [2, 4, 6]
-///
-pub fn map(over iterator: Iterator(a), with f: fn(a) -> b) -> Iterator(b) {
- iterator.continuation
- |> do_map(f)
- |> Iterator
-}
-
-fn do_append(first: fn() -> Action(a), second: fn() -> Action(a)) -> Action(a) {
- case first() {
- Continue(e, first) -> Continue(e, fn() { do_append(first, second) })
- Stop -> second()
+ /// Evaluates and discards the first N elements in an iterator, returning a new
+ /// iterator.
+ ///
+ /// If the iterator does not have enough elements an empty iterator is
+ /// returned.
+ ///
+ /// This function does not evaluate the elements of the iterator, the
+ /// computation is performed when the iterator is later run.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2, 3, 4, 5] |> from_list |> drop(up_to: 3) |> to_list
+ /// [4, 5]
+ ///
+ /// > [1, 2] |> from_list |> drop(up_to: 3) |> to_list
+ /// []
+ ///
+ pub fn drop(from iterator: Iterator(e), up_to desired: Int) -> Iterator(e) {
+ fn() { do_drop(iterator.continuation, desired) }
+ |> Iterator
}
-}
-/// Appends two iterators, producing a new iterator.
-///
-/// This function does not evaluate the elements of the iterators, the
-/// computation is performed when the resulting iterator is later run.
-///
-/// ## Examples
-///
-/// > [1, 2] |> from_list |> append([3, 4] |> from_list) |> to_list
-/// [1, 2, 3, 4]
-///
-pub fn append(to first: Iterator(a), suffix second: Iterator(a)) -> Iterator(a) {
- fn() { do_append(first.continuation, second.continuation) }
- |> Iterator
-}
-
-fn do_flatten(flattened: fn() -> Action(Iterator(a))) -> Action(a) {
- case flattened() {
- Stop -> Stop
- Continue(it, next_iterator) ->
- do_append(it.continuation, fn() { do_flatten(next_iterator) })
+ fn do_map(continuation: fn() -> Action(a), f: fn(a) -> b) -> fn() -> Action(b) {
+ fn() {
+ case continuation() {
+ Stop -> Stop
+ Continue(e, continuation) -> Continue(f(e), do_map(continuation, f))
+ }
+ }
}
-}
-/// Flattens an iterator of iterators, creating a new iterator.
-///
-/// This function does not evaluate the elements of the iterator, the
-/// computation is performed when the iterator is later run.
-///
-/// ## Examples
-///
-/// > from_list([[1, 2], [3, 4]]) |> map(from_list) |> flatten |> to_list
-/// [1, 2, 3, 4]
-///
-pub fn flatten(iterator: Iterator(Iterator(a))) -> Iterator(a) {
- fn() { do_flatten(iterator.continuation) }
- |> Iterator
-}
-
-/// Creates an iterator from an existing iterator and a transformation function.
-///
-/// Each element in the new iterator will be the result of calling the given
-/// function on the elements in the given iterator and then flattening the
-/// results.
-///
-/// This function does not evaluate the elements of the iterator, the
-/// computation is performed when the iterator is later run.
-///
-/// ## Examples
-///
-/// > [1, 2] |> from_list |> flat_map(fn(x) { from_list([x, x + 1]) }) |> to_list
-/// [1, 2, 2, 3]
-///
-pub fn flat_map(
- over iterator: Iterator(a),
- with f: fn(a) -> Iterator(b),
-) -> Iterator(b) {
- iterator
- |> map(f)
- |> flatten
-}
-
-fn do_filter(
- continuation: fn() -> Action(e),
- predicate: fn(e) -> Bool,
-) -> Action(e) {
- case continuation() {
- Stop -> Stop
- Continue(e, iterator) ->
- case predicate(e) {
- True -> Continue(e, fn() { do_filter(iterator, predicate) })
- False -> do_filter(iterator, predicate)
- }
+ /// Creates an iterator from an existing iterator and a transformation function.
+ ///
+ /// Each element in the new iterator will be the result of calling the given
+ /// function on the elements in the given iterator.
+ ///
+ /// This function does not evaluate the elements of the iterator, the
+ /// computation is performed when the iterator is later run.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2, 3] |> from_list |> map(fn(x) { x * 2 }) |> to_list
+ /// [2, 4, 6]
+ ///
+ pub fn map(over iterator: Iterator(a), with f: fn(a) -> b) -> Iterator(b) {
+ iterator.continuation
+ |> do_map(f)
+ |> Iterator
}
-}
-/// Creates an iterator from an existing iterator and a predicate function.
-///
-/// The new iterator will contain elements from the first iterator for which
-/// the given function returns `True`.
-///
-/// This function does not evaluate the elements of the iterator, the
-/// computation is performed when the iterator is later run.
-///
-/// ## Examples
-///
-/// > import gleam/int
-/// > [1, 2, 3, 4] |> from_list |> filter(int.is_even) |> to_list
-/// [2, 4]
-///
-pub fn filter(
- iterator: Iterator(a),
- for predicate: fn(a) -> Bool,
-) -> Iterator(a) {
- fn() { do_filter(iterator.continuation, predicate) }
- |> Iterator
-}
+ fn do_append(first: fn() -> Action(a), second: fn() -> Action(a)) -> Action(a) {
+ case first() {
+ Continue(e, first) -> Continue(e, fn() { do_append(first, second) })
+ Stop -> second()
+ }
+ }
-/// Creates an iterator that repeats a given iterator infinitely.
-///
-/// ## Examples
-///
-/// > [1, 2] |> from_list |> cycle |> take(6)
-/// [1, 2, 1, 2, 1, 2]
-///
-pub fn cycle(iterator: Iterator(a)) -> Iterator(a) {
- repeat(iterator)
- |> flatten
-}
+ /// Appends two iterators, producing a new iterator.
+ ///
+ /// This function does not evaluate the elements of the iterators, the
+ /// computation is performed when the resulting iterator is later run.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2] |> from_list |> append([3, 4] |> from_list) |> to_list
+ /// [1, 2, 3, 4]
+ ///
+ pub fn append(
+ to first: Iterator(a),
+ suffix second: Iterator(a),
+ ) -> Iterator(a) {
+ fn() { do_append(first.continuation, second.continuation) }
+ |> Iterator
+ }
-/// Creates an iterator of ints, starting at a given start int and stepping by
-/// one to a given end int.
-///
-/// ## Examples
-///
-/// > range(from: 1, to: 5) |> to_list
-/// [1, 2, 3, 4]
-///
-/// > range(from: 1, to: -2) |> to_list
-/// [1, 0, -1]
-///
-/// > range(from: 0, to: 0) |> to_list
-/// []
-///
-pub fn range(from start: Int, to stop: Int) -> Iterator(Int) {
- let increment = case start < stop {
- True -> 1
- False -> -1
- }
-
- let next_step = fn(current) {
- case current == stop {
- True -> Done
- False -> Next(current, current + increment)
+ fn do_flatten(flattened: fn() -> Action(Iterator(a))) -> Action(a) {
+ case flattened() {
+ Stop -> Stop
+ Continue(it, next_iterator) ->
+ do_append(it.continuation, fn() { do_flatten(next_iterator) })
}
}
- unfold(start, next_step)
-}
-
-fn do_find(continuation: fn() -> Action(a), f: fn(a) -> Bool) -> Result(a, Nil) {
- case continuation() {
- Stop -> Error(Nil)
- Continue(e, next) ->
- case f(e) {
- True -> Ok(e)
- False -> do_find(next, f)
- }
+ /// Flattens an iterator of iterators, creating a new iterator.
+ ///
+ /// This function does not evaluate the elements of the iterator, the
+ /// computation is performed when the iterator is later run.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([[1, 2], [3, 4]]) |> map(from_list) |> flatten |> to_list
+ /// [1, 2, 3, 4]
+ ///
+ pub fn flatten(iterator: Iterator(Iterator(a))) -> Iterator(a) {
+ fn() { do_flatten(iterator.continuation) }
+ |> Iterator
}
-}
-/// Finds the first element in a given iterator for which the given function returns
-/// True.
-///
-/// Returns `Error(Nil)` if the function does not return True for any of the
-/// elements.
-///
-/// ## Examples
-///
-/// > find(from_list([1, 2, 3]), fn(x) { x > 2 })
-/// Ok(3)
-///
-/// > find(from_list([1, 2, 3]), fn(x) { x > 4 })
-/// Error(Nil)
-///
-/// > find(empty(), fn(x) { True })
-/// Error(Nil)
-///
-pub fn find(
- in haystack: Iterator(a),
- one_that is_desired: fn(a) -> Bool,
-) -> Result(a, Nil) {
- haystack.continuation
- |> do_find(is_desired)
-}
+ /// Creates an iterator from an existing iterator and a transformation function.
+ ///
+ /// Each element in the new iterator will be the result of calling the given
+ /// function on the elements in the given iterator and then flattening the
+ /// results.
+ ///
+ /// This function does not evaluate the elements of the iterator, the
+ /// computation is performed when the iterator is later run.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2] |> from_list |> flat_map(fn(x) { from_list([x, x + 1]) }) |> to_list
+ /// [1, 2, 2, 3]
+ ///
+ pub fn flat_map(
+ over iterator: Iterator(a),
+ with f: fn(a) -> Iterator(b),
+ ) -> Iterator(b) {
+ iterator
+ |> map(f)
+ |> flatten
+ }
-fn do_index(
- continuation: fn() -> Action(element),
- next: Int,
-) -> fn() -> Action(#(Int, element)) {
- fn() {
+ fn do_filter(
+ continuation: fn() -> Action(e),
+ predicate: fn(e) -> Bool,
+ ) -> Action(e) {
case continuation() {
Stop -> Stop
- Continue(e, continuation) ->
- Continue(#(next, e), do_index(continuation, next + 1))
+ Continue(e, iterator) ->
+ case predicate(e) {
+ True -> Continue(e, fn() { do_filter(iterator, predicate) })
+ False -> do_filter(iterator, predicate)
+ }
}
}
-}
-/// Wraps values yielded from an iterator with indices, starting from 0.
-///
-/// ## Examples
-///
-/// > from_list(["a", "b", "c"]) |> index |> to_list
-/// [#(0, "a"), #(1, "b"), #(2, "c")]
-///
-pub fn index(over iterator: Iterator(element)) -> Iterator(#(Int, element)) {
- iterator.continuation
- |> do_index(0)
- |> Iterator
-}
+ /// Creates an iterator from an existing iterator and a predicate function.
+ ///
+ /// The new iterator will contain elements from the first iterator for which
+ /// the given function returns `True`.
+ ///
+ /// This function does not evaluate the elements of the iterator, the
+ /// computation is performed when the iterator is later run.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/int
+ /// > [1, 2, 3, 4] |> from_list |> filter(int.is_even) |> to_list
+ /// [2, 4]
+ ///
+ pub fn filter(
+ iterator: Iterator(a),
+ for predicate: fn(a) -> Bool,
+ ) -> Iterator(a) {
+ fn() { do_filter(iterator.continuation, predicate) }
+ |> Iterator
+ }
-/// Creates an iterator that inifinitely applies a function to a value.
-///
-/// ## Examples
-///
-/// > iterate(1, fn(n) { n * 3 }) |> take(5)
-/// [1, 3, 9, 27, 81]
-///
-pub fn iterate(
- from initial: element,
- with f: fn(element) -> element,
-) -> Iterator(element) {
- unfold(initial, fn(element) { Next(element, f(element)) })
-}
+ /// Creates an iterator that repeats a given iterator infinitely.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2] |> from_list |> cycle |> take(6)
+ /// [1, 2, 1, 2, 1, 2]
+ ///
+ pub fn cycle(iterator: Iterator(a)) -> Iterator(a) {
+ repeat(iterator)
+ |> flatten
+ }
+
+ /// Creates an iterator of ints, starting at a given start int and stepping by
+ /// one to a given end int.
+ ///
+ /// ## Examples
+ ///
+ /// > range(from: 1, to: 5) |> to_list
+ /// [1, 2, 3, 4]
+ ///
+ /// > range(from: 1, to: -2) |> to_list
+ /// [1, 0, -1]
+ ///
+ /// > range(from: 0, to: 0) |> to_list
+ /// []
+ ///
+ pub fn range(from start: Int, to stop: Int) -> Iterator(Int) {
+ let increment = case start < stop {
+ True -> 1
+ False -> -1
+ }
+
+ let next_step = fn(current) {
+ case current == stop {
+ True -> Done
+ False -> Next(current, current + increment)
+ }
+ }
+
+ unfold(start, next_step)
+ }
-fn do_take_while(
- continuation: fn() -> Action(element),
- predicate: fn(element) -> Bool,
-) -> fn() -> Action(element) {
- fn() {
+ fn do_find(
+ continuation: fn() -> Action(a),
+ f: fn(a) -> Bool,
+ ) -> Result(a, Nil) {
case continuation() {
- Stop -> Stop
+ Stop -> Error(Nil)
Continue(e, next) ->
- case predicate(e) {
- False -> Stop
- True -> Continue(e, do_take_while(next, predicate))
+ case f(e) {
+ True -> Ok(e)
+ False -> do_find(next, f)
}
}
}
-}
-/// Creates an iterator that yields elements while the predicate returns `True`.
-///
-/// ## Examples
-///
-/// > from_list([1, 2, 3, 2, 4]) |> take_while(satisfying: fn(x) { x < 3 }) |> to_list
-/// [1, 2]
-///
-pub fn take_while(
- in iterator: Iterator(element),
- satisfying predicate: fn(element) -> Bool,
-) -> Iterator(element) {
- iterator.continuation
- |> do_take_while(predicate)
- |> Iterator
-}
+ /// Finds the first element in a given iterator for which the given function returns
+ /// True.
+ ///
+ /// Returns `Error(Nil)` if the function does not return True for any of the
+ /// elements.
+ ///
+ /// ## Examples
+ ///
+ /// > find(from_list([1, 2, 3]), fn(x) { x > 2 })
+ /// Ok(3)
+ ///
+ /// > find(from_list([1, 2, 3]), fn(x) { x > 4 })
+ /// Error(Nil)
+ ///
+ /// > find(empty(), fn(x) { True })
+ /// Error(Nil)
+ ///
+ pub fn find(
+ in haystack: Iterator(a),
+ one_that is_desired: fn(a) -> Bool,
+ ) -> Result(a, Nil) {
+ haystack.continuation
+ |> do_find(is_desired)
+ }
-fn do_drop_while(
- continuation: fn() -> Action(element),
- predicate: fn(element) -> Bool,
-) -> Action(element) {
- case continuation() {
- Stop -> Stop
- Continue(e, next) ->
- case predicate(e) {
- False -> Continue(e, next)
- True -> do_drop_while(next, predicate)
+ fn do_index(
+ continuation: fn() -> Action(element),
+ next: Int,
+ ) -> fn() -> Action(#(Int, element)) {
+ fn() {
+ case continuation() {
+ Stop -> Stop
+ Continue(e, continuation) ->
+ Continue(#(next, e), do_index(continuation, next + 1))
}
+ }
}
-}
-/// Creates an iterator that drops elements while the predicate returns `True`,
-/// and then yields the remaining elements.
-///
-/// ## Examples
-///
-/// > from_list([1, 2, 3, 4, 2, 5]) |> drop_while(satisfying: fn(x) { x < 4 }) |> to_list
-/// [4, 2, 5]
-///
-pub fn drop_while(
- in iterator: Iterator(element),
- satisfying predicate: fn(element) -> Bool,
-) -> Iterator(element) {
- fn() { do_drop_while(iterator.continuation, predicate) }
- |> Iterator
-}
+ /// Wraps values yielded from an iterator with indices, starting from 0.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list(["a", "b", "c"]) |> index |> to_list
+ /// [#(0, "a"), #(1, "b"), #(2, "c")]
+ ///
+ pub fn index(over iterator: Iterator(element)) -> Iterator(#(Int, element)) {
+ iterator.continuation
+ |> do_index(0)
+ |> Iterator
+ }
-fn do_scan(
- continuation: fn() -> Action(element),
- f: fn(element, acc) -> acc,
- accumulator: acc,
-) -> fn() -> Action(acc) {
- fn() {
- case continuation() {
- Stop -> Stop
- Continue(el, next) -> {
- let accumulated = f(el, accumulator)
- Continue(accumulated, do_scan(next, f, accumulated))
+ /// Creates an iterator that inifinitely applies a function to a value.
+ ///
+ /// ## Examples
+ ///
+ /// > iterate(1, fn(n) { n * 3 }) |> take(5)
+ /// [1, 3, 9, 27, 81]
+ ///
+ pub fn iterate(
+ from initial: element,
+ with f: fn(element) -> element,
+ ) -> Iterator(element) {
+ unfold(initial, fn(element) { Next(element, f(element)) })
+ }
+
+ fn do_take_while(
+ continuation: fn() -> Action(element),
+ predicate: fn(element) -> Bool,
+ ) -> fn() -> Action(element) {
+ fn() {
+ case continuation() {
+ Stop -> Stop
+ Continue(e, next) ->
+ case predicate(e) {
+ False -> Stop
+ True -> Continue(e, do_take_while(next, predicate))
+ }
}
}
}
-}
-/// Creates an iterator from an existing iterator and a stateful function.
-///
-/// Specifically, this behaves like `fold`, but yields intermediate results.
-///
-/// ## Examples
-///
-/// Generate a sequence of partial sums:
-/// > from_list([1, 2, 3, 4, 5]) |> scan(from: 0, with: fn(el, acc) { acc + el }) |> to_list
-/// [1, 3, 6, 10, 15]
-///
-pub fn scan(
- over iterator: Iterator(element),
- from initial: acc,
- with f: fn(element, acc) -> acc,
-) -> Iterator(acc) {
- iterator.continuation
- |> do_scan(f, initial)
- |> Iterator
-}
+ /// Creates an iterator that yields elements while the predicate returns `True`.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([1, 2, 3, 2, 4]) |> take_while(satisfying: fn(x) { x < 3 }) |> to_list
+ /// [1, 2]
+ ///
+ pub fn take_while(
+ in iterator: Iterator(element),
+ satisfying predicate: fn(element) -> Bool,
+ ) -> Iterator(element) {
+ iterator.continuation
+ |> do_take_while(predicate)
+ |> Iterator
+ }
-fn do_zip(
- left: fn() -> Action(a),
- right: fn() -> Action(b),
-) -> fn() -> Action(#(a, b)) {
- fn() {
- case left() {
+ fn do_drop_while(
+ continuation: fn() -> Action(element),
+ predicate: fn(element) -> Bool,
+ ) -> Action(element) {
+ case continuation() {
Stop -> Stop
- Continue(el_left, next_left) ->
- case right() {
- Stop -> Stop
- Continue(el_right, next_right) ->
- Continue(#(el_left, el_right), do_zip(next_left, next_right))
+ Continue(e, next) ->
+ case predicate(e) {
+ False -> Continue(e, next)
+ True -> do_drop_while(next, predicate)
}
}
}
-}
-/// Zips two iterators together, emitting values from both
-/// until the shorter one runs out.
-///
-/// ## Examples
-///
-/// > from_list(["a", "b", "c"]) |> zip(range(20, 30)) |> to_list
-/// [#("a", 20), #("b", 21), #("c", 22)]
-///
-pub fn zip(left: Iterator(a), right: Iterator(b)) -> Iterator(#(a, b)) {
- do_zip(left.continuation, right.continuation)
- |> Iterator
-}
+ /// Creates an iterator that drops elements while the predicate returns `True`,
+ /// and then yields the remaining elements.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([1, 2, 3, 4, 2, 5]) |> drop_while(satisfying: fn(x) { x < 4 }) |> to_list
+ /// [4, 2, 5]
+ ///
+ pub fn drop_while(
+ in iterator: Iterator(element),
+ satisfying predicate: fn(element) -> Bool,
+ ) -> Iterator(element) {
+ fn() { do_drop_while(iterator.continuation, predicate) }
+ |> Iterator
+ }
-// Result of collecting a single chunk by key
-type Chunk(element, key) {
- AnotherBy(List(element), key, element, fn() -> Action(element))
- LastBy(List(element))
-}
+ fn do_scan(
+ continuation: fn() -> Action(element),
+ f: fn(element, acc) -> acc,
+ accumulator: acc,
+ ) -> fn() -> Action(acc) {
+ fn() {
+ case continuation() {
+ Stop -> Stop
+ Continue(el, next) -> {
+ let accumulated = f(el, accumulator)
+ Continue(accumulated, do_scan(next, f, accumulated))
+ }
+ }
+ }
+ }
+
+ /// Creates an iterator from an existing iterator and a stateful function.
+ ///
+ /// Specifically, this behaves like `fold`, but yields intermediate results.
+ ///
+ /// ## Examples
+ ///
+ /// Generate a sequence of partial sums:
+ /// > from_list([1, 2, 3, 4, 5]) |> scan(from: 0, with: fn(el, acc) { acc + el }) |> to_list
+ /// [1, 3, 6, 10, 15]
+ ///
+ pub fn scan(
+ over iterator: Iterator(element),
+ from initial: acc,
+ with f: fn(element, acc) -> acc,
+ ) -> Iterator(acc) {
+ iterator.continuation
+ |> do_scan(f, initial)
+ |> Iterator
+ }
-fn next_chunk(
- continuation: fn() -> Action(element),
- f: fn(element) -> key,
- previous_key: key,
- current_chunk: List(element),
-) -> Chunk(element, key) {
- case continuation() {
- Stop -> LastBy(list.reverse(current_chunk))
- Continue(e, next) -> {
- let key = f(e)
- case key == previous_key {
- True -> next_chunk(next, f, key, [e, ..current_chunk])
- False -> AnotherBy(list.reverse(current_chunk), key, e, next)
+ fn do_zip(
+ left: fn() -> Action(a),
+ right: fn() -> Action(b),
+ ) -> fn() -> Action(#(a, b)) {
+ fn() {
+ case left() {
+ Stop -> Stop
+ Continue(el_left, next_left) ->
+ case right() {
+ Stop -> Stop
+ Continue(el_right, next_right) ->
+ Continue(#(el_left, el_right), do_zip(next_left, next_right))
+ }
}
}
}
-}
-fn do_chunk(
- continuation: fn() -> Action(element),
- f: fn(element) -> key,
- previous_key: key,
- previous_element: element,
-) -> Action(List(element)) {
- case next_chunk(continuation, f, previous_key, [previous_element]) {
- LastBy(chunk) -> Continue(chunk, stop)
- AnotherBy(chunk, key, el, next) ->
- Continue(chunk, fn() { do_chunk(next, f, key, el) })
+ /// Zips two iterators together, emitting values from both
+ /// until the shorter one runs out.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list(["a", "b", "c"]) |> zip(range(20, 30)) |> to_list
+ /// [#("a", 20), #("b", 21), #("c", 22)]
+ ///
+ pub fn zip(left: Iterator(a), right: Iterator(b)) -> Iterator(#(a, b)) {
+ do_zip(left.continuation, right.continuation)
+ |> Iterator
}
-}
-/// Creates an iterator that emits chunks of elements
-/// for which `f` returns the same value.
-///
-/// ## Examples
-///
-/// > from_list([1, 2, 2, 3, 4, 4, 6, 7, 7]) |> chunk(by: fn(n) { n % 2 }) |> to_list
-/// [[1], [2, 2], [3], [4, 4, 6], [7, 7]]
-///
-pub fn chunk(
- over iterator: Iterator(element),
- by f: fn(element) -> key,
-) -> Iterator(List(element)) {
- fn() {
- case iterator.continuation() {
- Stop -> Stop
- Continue(e, next) -> do_chunk(next, f, f(e), e)
+ // Result of collecting a single chunk by key
+ type Chunk(element, key) {
+ AnotherBy(List(element), key, element, fn() -> Action(element))
+ LastBy(List(element))
+ }
+
+ fn next_chunk(
+ continuation: fn() -> Action(element),
+ f: fn(element) -> key,
+ previous_key: key,
+ current_chunk: List(element),
+ ) -> Chunk(element, key) {
+ case continuation() {
+ Stop -> LastBy(list.reverse(current_chunk))
+ Continue(e, next) -> {
+ let key = f(e)
+ case key == previous_key {
+ True -> next_chunk(next, f, key, [e, ..current_chunk])
+ False -> AnotherBy(list.reverse(current_chunk), key, e, next)
+ }
+ }
}
}
- |> Iterator
-}
-// Result of collecting a single sized chunk
-type SizedChunk(element) {
- Another(List(element), fn() -> Action(element))
- Last(List(element))
- None
-}
+ fn do_chunk(
+ continuation: fn() -> Action(element),
+ f: fn(element) -> key,
+ previous_key: key,
+ previous_element: element,
+ ) -> Action(List(element)) {
+ case next_chunk(continuation, f, previous_key, [previous_element]) {
+ LastBy(chunk) -> Continue(chunk, stop)
+ AnotherBy(chunk, key, el, next) ->
+ Continue(chunk, fn() { do_chunk(next, f, key, el) })
+ }
+ }
-fn next_sized_chunk(
- continuation: fn() -> Action(element),
- left: Int,
- current_chunk: List(element),
-) -> SizedChunk(element) {
- case continuation() {
- Stop ->
- case current_chunk {
- [] -> None
- remaining -> Last(list.reverse(remaining))
+ /// Creates an iterator that emits chunks of elements
+ /// for which `f` returns the same value.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([1, 2, 2, 3, 4, 4, 6, 7, 7]) |> chunk(by: fn(n) { n % 2 }) |> to_list
+ /// [[1], [2, 2], [3], [4, 4, 6], [7, 7]]
+ ///
+ pub fn chunk(
+ over iterator: Iterator(element),
+ by f: fn(element) -> key,
+ ) -> Iterator(List(element)) {
+ fn() {
+ case iterator.continuation() {
+ Stop -> Stop
+ Continue(e, next) -> do_chunk(next, f, f(e), e)
}
- Continue(e, next) -> {
- let chunk = [e, ..current_chunk]
- case left > 1 {
- False -> Another(list.reverse(chunk), next)
- True -> next_sized_chunk(next, left - 1, chunk)
+ }
+ |> Iterator
+ }
+
+ // Result of collecting a single sized chunk
+ type SizedChunk(element) {
+ Another(List(element), fn() -> Action(element))
+ Last(List(element))
+ None
+ }
+
+ fn next_sized_chunk(
+ continuation: fn() -> Action(element),
+ left: Int,
+ current_chunk: List(element),
+ ) -> SizedChunk(element) {
+ case continuation() {
+ Stop ->
+ case current_chunk {
+ [] -> None
+ remaining -> Last(list.reverse(remaining))
+ }
+ Continue(e, next) -> {
+ let chunk = [e, ..current_chunk]
+ case left > 1 {
+ False -> Another(list.reverse(chunk), next)
+ True -> next_sized_chunk(next, left - 1, chunk)
+ }
}
}
}
-}
-fn do_sized_chunk(
- continuation: fn() -> Action(element),
- count: Int,
-) -> fn() -> Action(List(element)) {
- fn() {
- case next_sized_chunk(continuation, count, []) {
- None -> Stop
- Last(chunk) -> Continue(chunk, stop)
- Another(chunk, next_element) ->
- Continue(chunk, do_sized_chunk(next_element, count))
+ fn do_sized_chunk(
+ continuation: fn() -> Action(element),
+ count: Int,
+ ) -> fn() -> Action(List(element)) {
+ fn() {
+ case next_sized_chunk(continuation, count, []) {
+ None -> Stop
+ Last(chunk) -> Continue(chunk, stop)
+ Another(chunk, next_element) ->
+ Continue(chunk, do_sized_chunk(next_element, count))
+ }
}
}
-}
-/// Creates an iterator that emits chunks of given size.
-///
-/// If the last chunk does not have `count` elements, it is yielded
-/// as a partial chunk, with less than `count` elements.
-///
-/// For any `count` less than 1 this function behaves as if it was set to 1.
-///
-/// ## Examples
-///
-/// > from_list([1, 2, 3, 4, 5, 6]) |> chunk(into: 2) |> to_list
-/// [[1, 2], [3, 4], [5, 6]]
-///
-/// > from_list([1, 2, 3, 4, 5, 6, 7, 8]) |> chunk(into: 3) |> to_list
-/// [[1, 2, 3], [4, 5, 6], [7, 8]]
-///
-pub fn sized_chunk(
- over iterator: Iterator(element),
- into count: Int,
-) -> Iterator(List(element)) {
- iterator.continuation
- |> do_sized_chunk(count)
- |> Iterator
-}
+ /// Creates an iterator that emits chunks of given size.
+ ///
+ /// If the last chunk does not have `count` elements, it is yielded
+ /// as a partial chunk, with less than `count` elements.
+ ///
+ /// For any `count` less than 1 this function behaves as if it was set to 1.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([1, 2, 3, 4, 5, 6]) |> chunk(into: 2) |> to_list
+ /// [[1, 2], [3, 4], [5, 6]]
+ ///
+ /// > from_list([1, 2, 3, 4, 5, 6, 7, 8]) |> chunk(into: 3) |> to_list
+ /// [[1, 2, 3], [4, 5, 6], [7, 8]]
+ ///
+ pub fn sized_chunk(
+ over iterator: Iterator(element),
+ into count: Int,
+ ) -> Iterator(List(element)) {
+ iterator.continuation
+ |> do_sized_chunk(count)
+ |> Iterator
+ }
-fn do_intersperse(
- continuation: fn() -> Action(element),
- separator: element,
-) -> Action(element) {
- case continuation() {
- Stop -> Stop
- Continue(e, next) -> {
- let next_interspersed = fn() { do_intersperse(next, separator) }
- Continue(separator, fn() { Continue(e, next_interspersed) })
+ fn do_intersperse(
+ continuation: fn() -> Action(element),
+ separator: element,
+ ) -> Action(element) {
+ case continuation() {
+ Stop -> Stop
+ Continue(e, next) -> {
+ let next_interspersed = fn() { do_intersperse(next, separator) }
+ Continue(separator, fn() { Continue(e, next_interspersed) })
+ }
}
}
-}
-/// Creates an iterator that yields the given element
-/// between elements emitted by the underlying iterator.
-///
-/// ## Examples
-///
-/// > empty() |> intersperse(with: 0) |> to_list
-/// []
-///
-/// > from_list([1]) |> intersperse(with: 0) |> to_list
-/// [1]
-///
-/// > from_list([1, 2, 3, 4, 5]) |> intersperse(with: 0) |> to_list
-/// [1, 0, 2, 0, 3, 0, 4, 0, 5]
-///
-pub fn intersperse(
- over iterator: Iterator(element),
- with elem: element,
-) -> Iterator(element) {
- fn() {
- case iterator.continuation() {
- Stop -> Stop
- Continue(e, next) -> Continue(e, fn() { do_intersperse(next, elem) })
+ /// Creates an iterator that yields the given element
+ /// between elements emitted by the underlying iterator.
+ ///
+ /// ## Examples
+ ///
+ /// > empty() |> intersperse(with: 0) |> to_list
+ /// []
+ ///
+ /// > from_list([1]) |> intersperse(with: 0) |> to_list
+ /// [1]
+ ///
+ /// > from_list([1, 2, 3, 4, 5]) |> intersperse(with: 0) |> to_list
+ /// [1, 0, 2, 0, 3, 0, 4, 0, 5]
+ ///
+ pub fn intersperse(
+ over iterator: Iterator(element),
+ with elem: element,
+ ) -> Iterator(element) {
+ fn() {
+ case iterator.continuation() {
+ Stop -> Stop
+ Continue(e, next) -> Continue(e, fn() { do_intersperse(next, elem) })
+ }
}
+ |> Iterator
}
- |> Iterator
-}
-fn do_any(
- continuation: fn() -> Action(element),
- predicate: fn(element) -> Bool,
-) -> Bool {
- case continuation() {
- Stop -> False
- Continue(e, next) -> predicate(e) || do_any(next, predicate)
+ fn do_any(
+ continuation: fn() -> Action(element),
+ predicate: fn(element) -> Bool,
+ ) -> Bool {
+ case continuation() {
+ Stop -> False
+ Continue(e, next) -> predicate(e) || do_any(next, predicate)
+ }
}
-}
-/// Returns `True` if any element emitted by the iterator satisfies the given predicate,
-/// `False` otherwise.
-///
-/// This function short-circuits once it finds a satisfying element.
-///
-/// An empty iterator results in `False`.
-///
-/// ## Examples
-///
-/// > empty() |> any(fn(n) { n % 2 == 0 })
-/// False
-///
-/// > from_list([1, 2, 5, 7, 9]) |> any(fn(n) { n % 2 == 0 })
-/// True
-///
-/// > from_list([1, 3, 5, 7, 9]) |> any(fn(n) { n % 2 == 0 })
-/// False
-///
-pub fn any(
- in iterator: Iterator(element),
- satisfying predicate: fn(element) -> Bool,
-) -> Bool {
- iterator.continuation
- |> do_any(predicate)
-}
+ /// Returns `True` if any element emitted by the iterator satisfies the given predicate,
+ /// `False` otherwise.
+ ///
+ /// This function short-circuits once it finds a satisfying element.
+ ///
+ /// An empty iterator results in `False`.
+ ///
+ /// ## Examples
+ ///
+ /// > empty() |> any(fn(n) { n % 2 == 0 })
+ /// False
+ ///
+ /// > from_list([1, 2, 5, 7, 9]) |> any(fn(n) { n % 2 == 0 })
+ /// True
+ ///
+ /// > from_list([1, 3, 5, 7, 9]) |> any(fn(n) { n % 2 == 0 })
+ /// False
+ ///
+ pub fn any(
+ in iterator: Iterator(element),
+ satisfying predicate: fn(element) -> Bool,
+ ) -> Bool {
+ iterator.continuation
+ |> do_any(predicate)
+ }
-fn do_all(
- continuation: fn() -> Action(element),
- predicate: fn(element) -> Bool,
-) -> Bool {
- case continuation() {
- Stop -> True
- Continue(e, next) -> predicate(e) && do_all(next, predicate)
+ fn do_all(
+ continuation: fn() -> Action(element),
+ predicate: fn(element) -> Bool,
+ ) -> Bool {
+ case continuation() {
+ Stop -> True
+ Continue(e, next) -> predicate(e) && do_all(next, predicate)
+ }
}
-}
-/// Returns `True` if all elements emitted by the iterator satisfy the given predicate,
-/// `False` otherwise.
-///
-/// This function short-circuits once it finds a non-satisfying element.
-///
-/// An empty iterator results in `True`.
-///
-/// ## Examples
-///
-/// > empty() |> all(fn(n) { n % 2 == 0 })
-/// True
-///
-/// > from_list([2, 4, 6, 8]) |> all(fn(n) { n % 2 == 0 })
-/// True
-///
-/// > from_list([2, 4, 5, 8]) |> all(fn(n) { n % 2 == 0 })
-/// False
-///
-pub fn all(
- in iterator: Iterator(element),
- satisfying predicate: fn(element) -> Bool,
-) -> Bool {
- iterator.continuation
- |> do_all(predicate)
-}
+ /// Returns `True` if all elements emitted by the iterator satisfy the given predicate,
+ /// `False` otherwise.
+ ///
+ /// This function short-circuits once it finds a non-satisfying element.
+ ///
+ /// An empty iterator results in `True`.
+ ///
+ /// ## Examples
+ ///
+ /// > empty() |> all(fn(n) { n % 2 == 0 })
+ /// True
+ ///
+ /// > from_list([2, 4, 6, 8]) |> all(fn(n) { n % 2 == 0 })
+ /// True
+ ///
+ /// > from_list([2, 4, 5, 8]) |> all(fn(n) { n % 2 == 0 })
+ /// False
+ ///
+ pub fn all(
+ in iterator: Iterator(element),
+ satisfying predicate: fn(element) -> Bool,
+ ) -> Bool {
+ iterator.continuation
+ |> do_all(predicate)
+ }
-fn update_group_with(
- el: element,
-) -> fn(Result(List(element), Nil)) -> List(element) {
- fn(maybe_group) {
- case maybe_group {
- Ok(group) -> [el, ..group]
- Error(Nil) -> [el]
+ fn update_group_with(
+ el: element,
+ ) -> fn(Result(List(element), Nil)) -> List(element) {
+ fn(maybe_group) {
+ case maybe_group {
+ Ok(group) -> [el, ..group]
+ Error(Nil) -> [el]
+ }
}
}
-}
-fn group_updater(
- f: fn(element) -> key,
-) -> fn(element, Map(key, List(element))) -> Map(key, List(element)) {
- fn(elem, groups) {
- groups
- |> map.update(f(elem), update_group_with(elem))
+ fn group_updater(
+ f: fn(element) -> key,
+ ) -> fn(element, Map(key, List(element))) -> Map(key, List(element)) {
+ fn(elem, groups) {
+ groups
+ |> map.update(f(elem), update_group_with(elem))
+ }
}
-}
-/// Returns a `Map(k, List(element))` of elements from the given iterator
-/// grouped with the given key function.
-///
-/// The order within each group is preserved from the iterator.
-///
-/// ## Examples
-///
-/// > from_list([1, 2, 3, 4, 5, 6]) |> group(by: fn(n) { n % 3 })
-/// map.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])])
-///
-pub fn group(
- in iterator: Iterator(element),
- by key: fn(element) -> key,
-) -> Map(key, List(element)) {
- iterator
- |> fold(map.new(), group_updater(key))
- |> map.map_values(fn(_, group) { list.reverse(group) })
-}
+ /// Returns a `Map(k, List(element))` of elements from the given iterator
+ /// grouped with the given key function.
+ ///
+ /// The order within each group is preserved from the iterator.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([1, 2, 3, 4, 5, 6]) |> group(by: fn(n) { n % 3 })
+ /// map.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])])
+ ///
+ pub fn group(
+ in iterator: Iterator(element),
+ by key: fn(element) -> key,
+ ) -> Map(key, List(element)) {
+ iterator
+ |> fold(map.new(), group_updater(key))
+ |> map.map_values(fn(_, group) { list.reverse(group) })
+ }
-/// This function acts similar to fold, but does not take an initial state.
-/// Instead, it starts from the first yielded element
-/// and combines it with each subsequent element in turn using the given function.
-/// The function is called as f(current_element, accumulator).
-///
-/// Returns `Ok` to indicate a successful run, and `Error` if called on an empty iterator.
-///
-/// ## Examples
-///
-/// > from_list([]) |> reduce(fn(x, y) { x + y })
-/// Error(Nil)
-///
-/// > from_list([1, 2, 3, 4, 5]) |> reduce(fn(x, y) { x + y })
-/// Ok(15)
-///
-pub fn reduce(
- over iterator: Iterator(e),
- with f: fn(e, e) -> e,
-) -> Result(e, Nil) {
- case iterator.continuation() {
- Stop -> Error(Nil)
- Continue(e, next) ->
- do_fold(next, f, e)
- |> Ok
+ /// This function acts similar to fold, but does not take an initial state.
+ /// Instead, it starts from the first yielded element
+ /// and combines it with each subsequent element in turn using the given function.
+ /// The function is called as f(current_element, accumulator).
+ ///
+ /// Returns `Ok` to indicate a successful run, and `Error` if called on an empty iterator.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([]) |> reduce(fn(x, y) { x + y })
+ /// Error(Nil)
+ ///
+ /// > from_list([1, 2, 3, 4, 5]) |> reduce(fn(x, y) { x + y })
+ /// Ok(15)
+ ///
+ pub fn reduce(
+ over iterator: Iterator(e),
+ with f: fn(e, e) -> e,
+ ) -> Result(e, Nil) {
+ case iterator.continuation() {
+ Stop -> Error(Nil)
+ Continue(e, next) ->
+ do_fold(next, f, e)
+ |> Ok
+ }
}
-}
-/// Returns the last element in the given iterator.
-///
-/// Returns `Error(Nil)` if the iterator is empty.
-///
-/// This function runs in linear time.
-///
-/// ## Examples
-///
-/// > empty() |> last
-/// Error(Nil)
-///
-/// > range(1, 10) |> last
-/// Ok(9)
-///
-pub fn last(iterator: Iterator(element)) -> Result(element, Nil) {
- iterator
- |> reduce(fn(elem, _) { elem })
-}
+ /// Returns the last element in the given iterator.
+ ///
+ /// Returns `Error(Nil)` if the iterator is empty.
+ ///
+ /// This function runs in linear time.
+ ///
+ /// ## Examples
+ ///
+ /// > empty() |> last
+ /// Error(Nil)
+ ///
+ /// > range(1, 10) |> last
+ /// Ok(9)
+ ///
+ pub fn last(iterator: Iterator(element)) -> Result(element, Nil) {
+ iterator
+ |> reduce(fn(elem, _) { elem })
+ }
-/// Creates an iterator that yields no elements.
-///
-/// ## Examples
-///
-/// > empty() |> to_list
-/// []
-///
-pub fn empty() -> Iterator(element) {
- Iterator(stop)
-}
+ /// Creates an iterator that yields no elements.
+ ///
+ /// ## Examples
+ ///
+ /// > empty() |> to_list
+ /// []
+ ///
+ pub fn empty() -> Iterator(element) {
+ Iterator(stop)
+ }
-/// Creates an iterator that yields exactly one element provided by calling the given function.
-///
-/// ## Examples
-///
-/// > once(fn() { 1 }) |> to_list
-/// [1]
-///
-pub fn once(f: fn() -> element) -> Iterator(element) {
- fn() { Continue(f(), stop) }
- |> Iterator
-}
+ /// Creates an iterator that yields exactly one element provided by calling the given function.
+ ///
+ /// ## Examples
+ ///
+ /// > once(fn() { 1 }) |> to_list
+ /// [1]
+ ///
+ pub fn once(f: fn() -> element) -> Iterator(element) {
+ fn() { Continue(f(), stop) }
+ |> Iterator
+ }
-/// Creates an iterator that yields the given element exactly once.
-///
-/// ## Examples
-///
-/// > single(1) |> to_list
-/// [1]
-///
-pub fn single(elem: element) -> Iterator(element) {
- once(fn() { elem })
-}
+ /// Creates an iterator that yields the given element exactly once.
+ ///
+ /// ## Examples
+ ///
+ /// > single(1) |> to_list
+ /// [1]
+ ///
+ pub fn single(elem: element) -> Iterator(element) {
+ once(fn() { elem })
+ }
-fn do_interleave(
- current: fn() -> Action(element),
- next: fn() -> Action(element),
-) -> Action(element) {
- case current() {
- Stop -> next()
- Continue(e, next_other) ->
- Continue(e, fn() { do_interleave(next, next_other) })
+ fn do_interleave(
+ current: fn() -> Action(element),
+ next: fn() -> Action(element),
+ ) -> Action(element) {
+ case current() {
+ Stop -> next()
+ Continue(e, next_other) ->
+ Continue(e, fn() { do_interleave(next, next_other) })
+ }
}
-}
-/// Creates an iterator that alternates between the two given iterators
-/// until both have run out.
-///
-/// ## Examples
-///
-/// > from_list([1, 2, 3, 4]) |> interleave(from_list([11, 12, 13, 14])) |> to_list
-/// [1, 11, 2, 12, 3, 13, 4, 14]
-///
-/// > from_list([1, 2, 3, 4]) |> interleave(from_list([100])) |> to_list
-/// [1, 100, 2, 3, 4]
-///
-pub fn interleave(
- left: Iterator(element),
- with right: Iterator(element),
-) -> Iterator(element) {
- fn() { do_interleave(left.continuation, right.continuation) }
- |> Iterator
+ /// Creates an iterator that alternates between the two given iterators
+ /// until both have run out.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([1, 2, 3, 4]) |> interleave(from_list([11, 12, 13, 14])) |> to_list
+ /// [1, 11, 2, 12, 3, 13, 4, 14]
+ ///
+ /// > from_list([1, 2, 3, 4]) |> interleave(from_list([100])) |> to_list
+ /// [1, 100, 2, 3, 4]
+ ///
+ pub fn interleave(
+ left: Iterator(element),
+ with right: Iterator(element),
+ ) -> Iterator(element) {
+ fn() { do_interleave(left.continuation, right.continuation) }
+ |> Iterator
+ }
}
diff --git a/src/gleam/list.gleam b/src/gleam/list.gleam
index 2a91733..33e32d1 100644
--- a/src/gleam/list.gleam
+++ b/src/gleam/list.gleam
@@ -18,1556 +18,1560 @@
//// }
////
-import gleam/int
-import gleam/pair
-import gleam/order.{Order}
-
-pub type List(elements) =
- List(elements)
-
-/// An error value returned by the `strict_zip` function.
-///
-pub type LengthMismatch {
- LengthMismatch
-}
+if erlang {
+ import gleam/int
+ import gleam/pair
+ import gleam/order.{Order}
+
+ pub type List(elements) =
+ List(elements)
+
+ /// An error value returned by the `strict_zip` function.
+ ///
+ pub type LengthMismatch {
+ LengthMismatch
+ }
-/// Counts the number of elements in a given list.
-///
-/// This function has to traverse the list to determine the number of elements,
-/// so it runs in linear time.
-///
-/// This function is natively implemented by the virtual machine and is highly
-/// optimised.
-///
-/// ## Examples
-///
-/// > length([])
-/// 0
-///
-/// > length([1])
-/// 1
-///
-/// > length([1, 2])
-/// 2
-///
-pub external fn length(of: List(a)) -> Int =
- "erlang" "length"
-
-/// Creates a new list from a given list containing the same elements but in the
-/// opposite order.
-///
-/// This function has to traverse the list to create the new reversed list, so
-/// it runs in linear time.
-///
-/// This function is natively implemented by the virtual machine and is highly
-/// optimised.
-///
-/// ## Examples
-///
-/// > reverse([])
-/// []
-///
-/// > reverse([1])
-/// [1]
-///
-/// > reverse([1, 2])
-/// [2, 1]
-///
-pub external fn reverse(List(a)) -> List(a) =
- "lists" "reverse"
-
-/// Determines whether or not the list is empty.
-///
-/// This function runs in constant time.
-///
-/// ## Examples
-///
-/// > is_empty([])
-/// True
-///
-/// > is_empty([1])
-/// False
-///
-/// > is_empty([1, 1])
-/// False
-///
-pub fn is_empty(list: List(a)) -> Bool {
- list == []
-}
+ /// Counts the number of elements in a given list.
+ ///
+ /// This function has to traverse the list to determine the number of elements,
+ /// so it runs in linear time.
+ ///
+ /// This function is natively implemented by the virtual machine and is highly
+ /// optimised.
+ ///
+ /// ## Examples
+ ///
+ /// > length([])
+ /// 0
+ ///
+ /// > length([1])
+ /// 1
+ ///
+ /// > length([1, 2])
+ /// 2
+ ///
+ pub external fn length(of: List(a)) -> Int =
+ "erlang" "length"
+
+ /// Creates a new list from a given list containing the same elements but in the
+ /// opposite order.
+ ///
+ /// This function has to traverse the list to create the new reversed list, so
+ /// it runs in linear time.
+ ///
+ /// This function is natively implemented by the virtual machine and is highly
+ /// optimised.
+ ///
+ /// ## Examples
+ ///
+ /// > reverse([])
+ /// []
+ ///
+ /// > reverse([1])
+ /// [1]
+ ///
+ /// > reverse([1, 2])
+ /// [2, 1]
+ ///
+ pub external fn reverse(List(a)) -> List(a) =
+ "lists" "reverse"
+
+ /// Determines whether or not the list is empty.
+ ///
+ /// This function runs in constant time.
+ ///
+ /// ## Examples
+ ///
+ /// > is_empty([])
+ /// True
+ ///
+ /// > is_empty([1])
+ /// False
+ ///
+ /// > is_empty([1, 1])
+ /// False
+ ///
+ pub fn is_empty(list: List(a)) -> Bool {
+ list == []
+ }
-/// Determines whether or not a given element exists within a given list.
-///
-/// This function traverses the list to find the element, so it runs in linear
-/// time.
-///
-/// ## Examples
-///
-/// > [] |> contains(any: 0)
-/// True
-///
-/// > [0] |> contains(any: 0)
-/// True
-///
-/// > [1] |> contains(any: 0)
-/// False
-///
-/// > [1, 1] |> contains(any: 0)
-/// False
-///
-/// > [1, 0] |> contains(any: 0)
-/// True
-///
-pub fn contains(list: List(a), any elem: a) -> Bool {
- case list {
- [] -> False
- [head, ..rest] -> head == elem || contains(rest, elem)
+ /// Determines whether or not a given element exists within a given list.
+ ///
+ /// This function traverses the list to find the element, so it runs in linear
+ /// time.
+ ///
+ /// ## Examples
+ ///
+ /// > [] |> contains(any: 0)
+ /// True
+ ///
+ /// > [0] |> contains(any: 0)
+ /// True
+ ///
+ /// > [1] |> contains(any: 0)
+ /// False
+ ///
+ /// > [1, 1] |> contains(any: 0)
+ /// False
+ ///
+ /// > [1, 0] |> contains(any: 0)
+ /// True
+ ///
+ pub fn contains(list: List(a), any elem: a) -> Bool {
+ case list {
+ [] -> False
+ [head, ..rest] -> head == elem || contains(rest, elem)
+ }
}
-}
-/// Gets the first element from the start of the list, if there is one.
-///
-/// ## Examples
-///
-/// > head([])
-/// Error(Nil)
-///
-/// > head([0])
-/// Ok(0)
-///
-/// > head([1, 2])
-/// Ok(1)
-///
-pub fn head(list: List(a)) -> Result(a, Nil) {
- case list {
- [] -> Error(Nil)
- [x, .._] -> Ok(x)
+ /// Gets the first element from the start of the list, if there is one.
+ ///
+ /// ## Examples
+ ///
+ /// > head([])
+ /// Error(Nil)
+ ///
+ /// > head([0])
+ /// Ok(0)
+ ///
+ /// > head([1, 2])
+ /// Ok(1)
+ ///
+ pub fn head(list: List(a)) -> Result(a, Nil) {
+ case list {
+ [] -> Error(Nil)
+ [x, .._] -> Ok(x)
+ }
}
-}
-/// Gets the list minus the first element. If the list is empty `Error(Nil)` is
-/// returned.
-///
-/// This function runs in constant time and does not make a copy of the list.
-///
-/// ## Examples
-///
-/// > tail([])
-/// Error(Nil)
-///
-/// > tail([0])
-/// Ok([])
-///
-/// > tail([1, 2])
-/// Ok([2])
-///
-pub fn tail(list: List(a)) -> Result(List(a), Nil) {
- case list {
- [] -> Error(Nil)
- [_, ..xs] -> Ok(xs)
+ /// Gets the list minus the first element. If the list is empty `Error(Nil)` is
+ /// returned.
+ ///
+ /// This function runs in constant time and does not make a copy of the list.
+ ///
+ /// ## Examples
+ ///
+ /// > tail([])
+ /// Error(Nil)
+ ///
+ /// > tail([0])
+ /// Ok([])
+ ///
+ /// > tail([1, 2])
+ /// Ok([2])
+ ///
+ pub fn tail(list: List(a)) -> Result(List(a), Nil) {
+ case list {
+ [] -> Error(Nil)
+ [_, ..xs] -> Ok(xs)
+ }
}
-}
-fn do_filter(list: List(a), fun: fn(a) -> Bool, acc: List(a)) -> List(a) {
- case list {
- [] -> reverse(acc)
- [x, ..xs] -> {
- let new_acc = case fun(x) {
- True -> [x, ..acc]
- False -> acc
+ fn do_filter(list: List(a), fun: fn(a) -> Bool, acc: List(a)) -> List(a) {
+ case list {
+ [] -> reverse(acc)
+ [x, ..xs] -> {
+ let new_acc = case fun(x) {
+ True -> [x, ..acc]
+ False -> acc
+ }
+ do_filter(xs, fun, new_acc)
}
- do_filter(xs, fun, new_acc)
}
}
-}
-/// Returns a new list containing only the elements from the first list for
-/// which the given functions returns `True`.
-///
-/// ## Examples
-///
-/// > filter([2, 4, 6, 1], fn(x) { x > 2 })
-/// [4, 6]
-///
-/// > filter([2, 4, 6, 1], fn(x) { x > 6 })
-/// []
-///
-pub fn filter(list: List(a), for predicate: fn(a) -> Bool) -> List(a) {
- do_filter(list, predicate, [])
-}
+ /// Returns a new list containing only the elements from the first list for
+ /// which the given functions returns `True`.
+ ///
+ /// ## Examples
+ ///
+ /// > filter([2, 4, 6, 1], fn(x) { x > 2 })
+ /// [4, 6]
+ ///
+ /// > filter([2, 4, 6, 1], fn(x) { x > 6 })
+ /// []
+ ///
+ pub fn filter(list: List(a), for predicate: fn(a) -> Bool) -> List(a) {
+ do_filter(list, predicate, [])
+ }
-fn do_filter_map(
- list: List(a),
- fun: fn(a) -> Result(b, e),
- acc: List(b),
-) -> List(b) {
- case list {
- [] -> reverse(acc)
- [x, ..xs] -> {
- let new_acc = case fun(x) {
- Ok(x) -> [x, ..acc]
- Error(_) -> acc
+ fn do_filter_map(
+ list: List(a),
+ fun: fn(a) -> Result(b, e),
+ acc: List(b),
+ ) -> List(b) {
+ case list {
+ [] -> reverse(acc)
+ [x, ..xs] -> {
+ let new_acc = case fun(x) {
+ Ok(x) -> [x, ..acc]
+ Error(_) -> acc
+ }
+ do_filter_map(xs, fun, new_acc)
}
- do_filter_map(xs, fun, new_acc)
}
}
-}
-
-/// Returns a new list containing only the elements from the first list for
-/// which the given functions returns `Ok(_)`.
-///
-/// ## Examples
-///
-/// > filter_map([2, 4, 6, 1], Error)
-/// []
-///
-/// > filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) })
-/// [3, 4, 6, 2]
-///
-pub fn filter_map(list: List(a), with fun: fn(a) -> Result(b, e)) -> List(b) {
- do_filter_map(list, fun, [])
-}
-fn do_map(list: List(a), fun: fn(a) -> b, acc: List(b)) -> List(b) {
- case list {
- [] -> reverse(acc)
- [x, ..xs] -> do_map(xs, fun, [fun(x), ..acc])
+ /// Returns a new list containing only the elements from the first list for
+ /// which the given functions returns `Ok(_)`.
+ ///
+ /// ## Examples
+ ///
+ /// > filter_map([2, 4, 6, 1], Error)
+ /// []
+ ///
+ /// > filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) })
+ /// [3, 4, 6, 2]
+ ///
+ pub fn filter_map(list: List(a), with fun: fn(a) -> Result(b, e)) -> List(b) {
+ do_filter_map(list, fun, [])
}
-}
-/// Returns a new list containing only the elements of the first list after the
-/// function has been applied to each one.
-///
-/// ## Examples
-///
-/// > map([2, 4, 6], fn(x) { x * 2 })
-/// [4, 8, 12]
-///
-pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) {
- do_map(list, fun, [])
-}
+ fn do_map(list: List(a), fun: fn(a) -> b, acc: List(b)) -> List(b) {
+ case list {
+ [] -> reverse(acc)
+ [x, ..xs] -> do_map(xs, fun, [fun(x), ..acc])
+ }
+ }
-/// Similar to map but also lets you pass around an accumulated value.
-///
-/// ## Examples
-///
-/// ```
-/// > map_fold(
-/// over: [1, 2, 3],
-/// from: 100,
-/// with: fn(i, memo) { #(i * 2, memo + i) }
-/// )
-/// #([2, 4, 6], 106)
-/// ```
-///
-pub fn map_fold(
- over list: List(a),
- from memo: memo,
- with fun: fn(a, memo) -> #(b, memo),
-) -> #(List(b), memo) {
- fold(
- over: list,
- from: #([], memo),
- with: fn(item, acc) {
- let #(items, current_memo) = acc
- let #(next_item, next_memo) = fun(item, current_memo)
- #([next_item, ..items], next_memo)
- },
- )
- |> pair.map_first(reverse)
-}
+ /// Returns a new list containing only the elements of the first list after the
+ /// function has been applied to each one.
+ ///
+ /// ## Examples
+ ///
+ /// > map([2, 4, 6], fn(x) { x * 2 })
+ /// [4, 8, 12]
+ ///
+ pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) {
+ do_map(list, fun, [])
+ }
-fn do_index_map(
- list: List(a),
- fun: fn(Int, a) -> b,
- index: Int,
- acc: List(b),
-) -> List(b) {
- case list {
- [] -> reverse(acc)
- [x, ..xs] -> do_index_map(xs, fun, index + 1, [fun(index, x), ..acc])
+ /// Similar to map but also lets you pass around an accumulated value.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > map_fold(
+ /// over: [1, 2, 3],
+ /// from: 100,
+ /// with: fn(i, memo) { #(i * 2, memo + i) }
+ /// )
+ /// #([2, 4, 6], 106)
+ /// ```
+ ///
+ pub fn map_fold(
+ over list: List(a),
+ from memo: memo,
+ with fun: fn(a, memo) -> #(b, memo),
+ ) -> #(List(b), memo) {
+ fold(
+ over: list,
+ from: #([], memo),
+ with: fn(item, acc) {
+ let #(items, current_memo) = acc
+ let #(next_item, next_memo) = fun(item, current_memo)
+ #([next_item, ..items], next_memo)
+ },
+ )
+ |> pair.map_first(reverse)
}
-}
-/// Returns a new list containing only the elements of the first list after the
-/// function has been applied to each one and their index.
-///
-/// The index starts at 0, so the first element is 0, the second is 1, and so
-/// on.
-///
-/// ## Examples
-///
-/// > index_map(["a", "b"], fn(i, x) { #(i, x) })
-/// [#(0, "a"), #(1, "b")]
-///
-pub fn index_map(list: List(a), with fun: fn(Int, a) -> b) -> List(b) {
- do_index_map(list, fun, 0, [])
-}
+ fn do_index_map(
+ list: List(a),
+ fun: fn(Int, a) -> b,
+ index: Int,
+ acc: List(b),
+ ) -> List(b) {
+ case list {
+ [] -> reverse(acc)
+ [x, ..xs] -> do_index_map(xs, fun, index + 1, [fun(index, x), ..acc])
+ }
+ }
-fn do_try_map(
- list: List(a),
- fun: fn(a) -> Result(b, e),
- acc: List(b),
-) -> Result(List(b), e) {
- case list {
- [] -> Ok(reverse(acc))
- [x, ..xs] ->
- case fun(x) {
- Ok(y) -> do_try_map(xs, fun, [y, ..acc])
- Error(error) -> Error(error)
- }
+ /// Returns a new list containing only the elements of the first list after the
+ /// function has been applied to each one and their index.
+ ///
+ /// The index starts at 0, so the first element is 0, the second is 1, and so
+ /// on.
+ ///
+ /// ## Examples
+ ///
+ /// > index_map(["a", "b"], fn(i, x) { #(i, x) })
+ /// [#(0, "a"), #(1, "b")]
+ ///
+ pub fn index_map(list: List(a), with fun: fn(Int, a) -> b) -> List(b) {
+ do_index_map(list, fun, 0, [])
}
-}
-/// Takes a function that returns a Result applies it to each element in a
-/// given list in tern.
-///
-/// If the function returns `Ok(new_value)` for all elements in the list then a
-/// list of the new values is returned.
-///
-/// If the function returns `Error(reason)` for any of the elements then it is
-/// returned immediately. None of the elements in the list are processed after
-/// one returns an `Error`.
-///
-/// ## Examples
-///
-/// > try_map([1, 2, 3], fn(x) { Ok(x + 2) })
-/// Ok([3, 4, 5])
-///
-/// > try_map([1, 2, 3], fn(x) { Error(0) })
-/// Error(0)
-///
-/// > try_map([[1], [2, 3]], head)
-/// Ok([1, 2])
-///
-/// > try_map([[1], [], [2]], head)
-/// Error(Nil)
-///
-pub fn try_map(
- over list: List(a),
- with fun: fn(a) -> Result(b, e),
-) -> Result(List(b), e) {
- do_try_map(list, fun, [])
-}
+ fn do_try_map(
+ list: List(a),
+ fun: fn(a) -> Result(b, e),
+ acc: List(b),
+ ) -> Result(List(b), e) {
+ case list {
+ [] -> Ok(reverse(acc))
+ [x, ..xs] ->
+ case fun(x) {
+ Ok(y) -> do_try_map(xs, fun, [y, ..acc])
+ Error(error) -> Error(error)
+ }
+ }
+ }
-/// Returns a list that is the given list with up to the given number of
-/// elements removed from the front of the list.
-///
-/// If the element has less than the number of elements an empty list is
-/// returned.
-///
-/// This function runs in linear time but does not copy the list.
-///
-/// ## Examples
-///
-/// > drop([1, 2, 3, 4], 2)
-/// [3, 4]
-///
-/// > drop([1, 2, 3, 4], 9)
-/// []
-///
-pub fn drop(from list: List(a), up_to n: Int) -> List(a) {
- case n <= 0 {
- True -> list
- False ->
- case list {
- [] -> []
- [_, ..xs] -> drop(xs, n - 1)
- }
+ /// Takes a function that returns a Result applies it to each element in a
+ /// given list in tern.
+ ///
+ /// If the function returns `Ok(new_value)` for all elements in the list then a
+ /// list of the new values is returned.
+ ///
+ /// If the function returns `Error(reason)` for any of the elements then it is
+ /// returned immediately. None of the elements in the list are processed after
+ /// one returns an `Error`.
+ ///
+ /// ## Examples
+ ///
+ /// > try_map([1, 2, 3], fn(x) { Ok(x + 2) })
+ /// Ok([3, 4, 5])
+ ///
+ /// > try_map([1, 2, 3], fn(x) { Error(0) })
+ /// Error(0)
+ ///
+ /// > try_map([[1], [2, 3]], head)
+ /// Ok([1, 2])
+ ///
+ /// > try_map([[1], [], [2]], head)
+ /// Error(Nil)
+ ///
+ pub fn try_map(
+ over list: List(a),
+ with fun: fn(a) -> Result(b, e),
+ ) -> Result(List(b), e) {
+ do_try_map(list, fun, [])
}
-}
-fn do_take(list: List(a), n: Int, acc: List(a)) -> List(a) {
- case n <= 0 {
- True -> reverse(acc)
- False ->
- case list {
- [] -> reverse(acc)
- [x, ..xs] -> do_take(xs, n - 1, [x, ..acc])
- }
+ /// Returns a list that is the given list with up to the given number of
+ /// elements removed from the front of the list.
+ ///
+ /// If the element has less than the number of elements an empty list is
+ /// returned.
+ ///
+ /// This function runs in linear time but does not copy the list.
+ ///
+ /// ## Examples
+ ///
+ /// > drop([1, 2, 3, 4], 2)
+ /// [3, 4]
+ ///
+ /// > drop([1, 2, 3, 4], 9)
+ /// []
+ ///
+ pub fn drop(from list: List(a), up_to n: Int) -> List(a) {
+ case n <= 0 {
+ True -> list
+ False ->
+ case list {
+ [] -> []
+ [_, ..xs] -> drop(xs, n - 1)
+ }
+ }
}
-}
-/// Returns a list containing the first given number of elements from the given
-/// list.
-///
-/// If the element has less than the number of elements then the full list is
-/// returned.
-///
-/// This function runs in linear time but does not copy the list.
-///
-/// ## Examples
-///
-/// > take([1, 2, 3, 4], 2)
-/// [1, 2]
-///
-/// > take([1, 2, 3, 4], 9)
-/// [1, 2, 3, 4]
-///
-pub fn take(from list: List(a), up_to n: Int) -> List(a) {
- do_take(list, n, [])
-}
+ fn do_take(list: List(a), n: Int, acc: List(a)) -> List(a) {
+ case n <= 0 {
+ True -> reverse(acc)
+ False ->
+ case list {
+ [] -> reverse(acc)
+ [x, ..xs] -> do_take(xs, n - 1, [x, ..acc])
+ }
+ }
+ }
-/// Returns a new empty list.
-///
-/// ## Examples
-///
-/// > new()
-/// []
-///
-pub fn new() -> List(a) {
- []
-}
+ /// Returns a list containing the first given number of elements from the given
+ /// list.
+ ///
+ /// If the element has less than the number of elements then the full list is
+ /// returned.
+ ///
+ /// This function runs in linear time but does not copy the list.
+ ///
+ /// ## Examples
+ ///
+ /// > take([1, 2, 3, 4], 2)
+ /// [1, 2]
+ ///
+ /// > take([1, 2, 3, 4], 9)
+ /// [1, 2, 3, 4]
+ ///
+ pub fn take(from list: List(a), up_to n: Int) -> List(a) {
+ do_take(list, n, [])
+ }
-/// Joins one list onto the end of another.
-///
-/// This function runs in linear time, and it traverses and copies the first
-/// list.
-///
-/// ## Examples
-///
-/// > append([1, 2], [3])
-/// [1, 2, 3]
-///
-pub external fn append(List(a), List(a)) -> List(a) =
- "lists" "append"
-
-fn do_flatten(lists: List(List(a)), acc: List(a)) -> List(a) {
- case lists {
- [] -> acc
- [l, ..rest] -> do_flatten(rest, append(acc, l))
+ /// Returns a new empty list.
+ ///
+ /// ## Examples
+ ///
+ /// > new()
+ /// []
+ ///
+ pub fn new() -> List(a) {
+ []
}
-}
-/// Flattens a list of lists into a single list.
-///
-/// This function runs in linear time, and it traverses and copies all the
-/// inner lists.
-///
-/// ## Examples
-///
-/// > flatten([[1], [2, 3], []])
-/// [1, 2, 3]
-///
-pub fn flatten(lists: List(List(a))) -> List(a) {
- do_flatten(lists, [])
-}
+ /// Joins one list onto the end of another.
+ ///
+ /// This function runs in linear time, and it traverses and copies the first
+ /// list.
+ ///
+ /// ## Examples
+ ///
+ /// > append([1, 2], [3])
+ /// [1, 2, 3]
+ ///
+ pub external fn append(List(a), List(a)) -> List(a) =
+ "lists" "append"
+
+ fn do_flatten(lists: List(List(a)), acc: List(a)) -> List(a) {
+ case lists {
+ [] -> acc
+ [l, ..rest] -> do_flatten(rest, append(acc, l))
+ }
+ }
-/// Map and flatten the result
-///
-/// ## Examples
-///
-/// ```
-/// > flat_map([2, 4, 6], fn(x) { [x, x + 1] })
-/// [2, 3, 4, 5, 6, 7]
-/// ```
-///
-pub fn flat_map(over list: List(a), with fun: fn(a) -> List(b)) -> List(b) {
- map(list, fun)
- |> flatten
-}
+ /// Flattens a list of lists into a single list.
+ ///
+ /// This function runs in linear time, and it traverses and copies all the
+ /// inner lists.
+ ///
+ /// ## Examples
+ ///
+ /// > flatten([[1], [2, 3], []])
+ /// [1, 2, 3]
+ ///
+ pub fn flatten(lists: List(List(a))) -> List(a) {
+ do_flatten(lists, [])
+ }
-/// Reduces a list of elements into a single value by calling a given function
-/// on each element, going from left to right.
-///
-/// `fold([1, 2, 3], 0, add)` is the equivalent of `add(3, add(2, add(1, 0)))`.
-///
-/// This function runs in linear time.
-///
-pub fn fold(over list: List(a), from initial: b, with fun: fn(a, b) -> b) -> b {
- case list {
- [] -> initial
- [x, ..rest] -> fold(rest, fun(x, initial), fun)
+ /// Map and flatten the result
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > flat_map([2, 4, 6], fn(x) { [x, x + 1] })
+ /// [2, 3, 4, 5, 6, 7]
+ /// ```
+ ///
+ pub fn flat_map(over list: List(a), with fun: fn(a) -> List(b)) -> List(b) {
+ map(list, fun)
+ |> flatten
}
-}
-/// Reduces a list of elements into a single value by calling a given function
-/// on each element, going from right to left.
-///
-/// `fold_right([1, 2, 3], 0, add)` is the equivalent of
-/// `add(1, add(2, add(3, 0)))`.
-///
-/// This function runs in linear time.
-///
-/// Unlike `fold` this function is not tail recursive. Where possible use
-/// `fold` instead as it will use less memory.
-///
-pub fn fold_right(
- over list: List(a),
- from initial: b,
- with fun: fn(a, b) -> b,
-) -> b {
- case list {
- [] -> initial
- [x, ..rest] -> fun(x, fold_right(rest, initial, fun))
+ /// Reduces a list of elements into a single value by calling a given function
+ /// on each element, going from left to right.
+ ///
+ /// `fold([1, 2, 3], 0, add)` is the equivalent of `add(3, add(2, add(1, 0)))`.
+ ///
+ /// This function runs in linear time.
+ ///
+ pub fn fold(over list: List(a), from initial: b, with fun: fn(a, b) -> b) -> b {
+ case list {
+ [] -> initial
+ [x, ..rest] -> fold(rest, fun(x, initial), fun)
+ }
}
-}
-fn do_index_fold(
- over: List(a),
- acc: b,
- with: fn(Int, a, b) -> b,
- index: Int,
-) -> b {
- case over {
- [] -> acc
- [first, ..rest] ->
- do_index_fold(rest, with(index, first, acc), with, index + 1)
+ /// Reduces a list of elements into a single value by calling a given function
+ /// on each element, going from right to left.
+ ///
+ /// `fold_right([1, 2, 3], 0, add)` is the equivalent of
+ /// `add(1, add(2, add(3, 0)))`.
+ ///
+ /// This function runs in linear time.
+ ///
+ /// Unlike `fold` this function is not tail recursive. Where possible use
+ /// `fold` instead as it will use less memory.
+ ///
+ pub fn fold_right(
+ over list: List(a),
+ from initial: b,
+ with fun: fn(a, b) -> b,
+ ) -> b {
+ case list {
+ [] -> initial
+ [x, ..rest] -> fun(x, fold_right(rest, initial, fun))
+ }
}
-}
-/// Like fold but the folding function also receives the index of the current element.
-///
-/// ## Examples
-///
-/// ```
-/// ["a", "b", "c"]
-/// |> list.index_fold([], fn(index, item, acc) { ... })
-/// ```
-///
-pub fn index_fold(
- over over: List(a),
- from initial: b,
- with fun: fn(Int, a, b) -> b,
-) -> b {
- do_index_fold(over, initial, fun, 0)
-}
+ fn do_index_fold(
+ over: List(a),
+ acc: b,
+ with: fn(Int, a, b) -> b,
+ index: Int,
+ ) -> b {
+ case over {
+ [] -> acc
+ [first, ..rest] ->
+ do_index_fold(rest, with(index, first, acc), with, index + 1)
+ }
+ }
-/// A variant of fold that might fail.
-///
-/// The folding function should return `Result(accumulator, error)
-/// If the returned value is `Ok(accumulator)` try_fold will try the next value in the list.
-/// If the returned value is `Error(error)` try_fold will stop and return that error.
-///
-/// ## Examples
-///
-/// ```
-/// [1, 2, 3, 4]
-/// |> try_fold(0, fn(i, acc) {
-/// case i < 3 {
-/// True -> Ok(acc + i)
-/// False -> Error(Nil)
-/// }
-/// })
-/// ```
-///
-pub fn try_fold(
- over collection: List(a),
- from accumulator: b,
- with fun: fn(a, b) -> Result(b, e),
-) -> Result(b, e) {
- case collection {
- [] -> Ok(accumulator)
- [first, ..rest] ->
- case fun(first, accumulator) {
- Ok(next_accumulator) -> try_fold(rest, next_accumulator, fun)
- Error(err) -> Error(err)
- }
+ /// Like fold but the folding function also receives the index of the current element.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// ["a", "b", "c"]
+ /// |> list.index_fold([], fn(index, item, acc) { ... })
+ /// ```
+ ///
+ pub fn index_fold(
+ over over: List(a),
+ from initial: b,
+ with fun: fn(Int, a, b) -> b,
+ ) -> b {
+ do_index_fold(over, initial, fun, 0)
}
-}
-pub type ContinueOrStop(a) {
- Continue(a)
- Stop(a)
-}
+ /// A variant of fold that might fail.
+ ///
+ /// The folding function should return `Result(accumulator, error)
+ /// If the returned value is `Ok(accumulator)` try_fold will try the next value in the list.
+ /// If the returned value is `Error(error)` try_fold will stop and return that error.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// [1, 2, 3, 4]
+ /// |> try_fold(0, fn(i, acc) {
+ /// case i < 3 {
+ /// True -> Ok(acc + i)
+ /// False -> Error(Nil)
+ /// }
+ /// })
+ /// ```
+ ///
+ pub fn try_fold(
+ over collection: List(a),
+ from accumulator: b,
+ with fun: fn(a, b) -> Result(b, e),
+ ) -> Result(b, e) {
+ case collection {
+ [] -> Ok(accumulator)
+ [first, ..rest] ->
+ case fun(first, accumulator) {
+ Ok(next_accumulator) -> try_fold(rest, next_accumulator, fun)
+ Error(err) -> Error(err)
+ }
+ }
+ }
-/// A variant of fold that allows to stop folding earlier.
-///
-/// The folding function should return `ContinueOrStop(accumulator)
-/// If the returned value is `Continue(accumulator)` fold_until will try the next value in the list.
-/// If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator.
-///
-/// ## Examples
-///
-/// ```
-/// [1, 2, 3, 4]
-/// |> fold_until(0, fn(i, acc) {
-/// case i < 3 {
-/// True -> Continue(acc + i)
-/// False -> Stop(acc)
-/// }
-/// })
-/// ```
-///
-pub fn fold_until(
- over collection: List(a),
- from accumulator: b,
- with fun: fn(a, b) -> ContinueOrStop(b),
-) -> b {
- case collection {
- [] -> accumulator
- [first, ..rest] ->
- case fun(first, accumulator) {
- Continue(next_accumulator) -> fold_until(rest, next_accumulator, fun)
- Stop(b) -> b
- }
+ pub type ContinueOrStop(a) {
+ Continue(a)
+ Stop(a)
}
-}
-/// Finds the first element in a given list for which the given function returns
-/// True.
-///
-/// Returns `Error(Nil)` if no the function does not return True for any of the
-/// elements.
-///
-/// ## Examples
-///
-/// > find([1, 2, 3], fn(x) { x > 2 })
-/// Ok(3)
-///
-/// > find([1, 2, 3], fn(x) { x > 4 })
-/// Error(Nil)
-///
-/// > find([], fn(x) { True })
-/// Error(Nil)
-///
-pub fn find(
- in haystack: List(a),
- one_that is_desired: fn(a) -> Bool,
-) -> Result(a, Nil) {
- case haystack {
- [] -> Error(Nil)
- [x, ..rest] ->
- case is_desired(x) {
- True -> Ok(x)
- _ -> find(in: rest, one_that: is_desired)
- }
+ /// A variant of fold that allows to stop folding earlier.
+ ///
+ /// The folding function should return `ContinueOrStop(accumulator)
+ /// If the returned value is `Continue(accumulator)` fold_until will try the next value in the list.
+ /// If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// [1, 2, 3, 4]
+ /// |> fold_until(0, fn(i, acc) {
+ /// case i < 3 {
+ /// True -> Continue(acc + i)
+ /// False -> Stop(acc)
+ /// }
+ /// })
+ /// ```
+ ///
+ pub fn fold_until(
+ over collection: List(a),
+ from accumulator: b,
+ with fun: fn(a, b) -> ContinueOrStop(b),
+ ) -> b {
+ case collection {
+ [] -> accumulator
+ [first, ..rest] ->
+ case fun(first, accumulator) {
+ Continue(next_accumulator) -> fold_until(rest, next_accumulator, fun)
+ Stop(b) -> b
+ }
+ }
}
-}
-/// Finds the first element in a given list for which the given function returns
-/// `Ok(new_value)` and return the new value for that element.
-///
-/// Returns `Error(Nil)` if no the function does not return Ok for any of the
-/// elements.
-///
-/// ## Examples
-///
-/// > find_map([[], [2], [3]], head)
-/// Ok(2)
-///
-/// > find_map([[], []], head)
-/// Error(Nil)
-///
-/// > find_map([], head)
-/// Error(Nil)
-///
-pub fn find_map(
- in haystack: List(a),
- with fun: fn(a) -> Result(b, c),
-) -> Result(b, Nil) {
- case haystack {
- [] -> Error(Nil)
- [x, ..rest] ->
- case fun(x) {
- Ok(x) -> Ok(x)
- _ -> find_map(in: rest, with: fun)
- }
+ /// Finds the first element in a given list for which the given function returns
+ /// True.
+ ///
+ /// Returns `Error(Nil)` if no the function does not return True for any of the
+ /// elements.
+ ///
+ /// ## Examples
+ ///
+ /// > find([1, 2, 3], fn(x) { x > 2 })
+ /// Ok(3)
+ ///
+ /// > find([1, 2, 3], fn(x) { x > 4 })
+ /// Error(Nil)
+ ///
+ /// > find([], fn(x) { True })
+ /// Error(Nil)
+ ///
+ pub fn find(
+ in haystack: List(a),
+ one_that is_desired: fn(a) -> Bool,
+ ) -> Result(a, Nil) {
+ case haystack {
+ [] -> Error(Nil)
+ [x, ..rest] ->
+ case is_desired(x) {
+ True -> Ok(x)
+ _ -> find(in: rest, one_that: is_desired)
+ }
+ }
}
-}
-/// Returns True if the given function returns True for all the elements in
-/// the given list. If the function returns False for any of the elements it
-/// immediately returns False without checking the rest of the list.
-///
-/// ## Examples
-///
-/// > all([], fn(x) { x > 3 })
-/// True
-///
-/// > all([4, 5], fn(x) { x > 3 })
-/// True
-///
-/// > all([4, 3], fn(x) { x > 3 })
-/// False
-///
-pub fn all(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool {
- case list {
- [] -> True
- [x, ..rest] -> predicate(x) && all(rest, predicate)
+ /// Finds the first element in a given list for which the given function returns
+ /// `Ok(new_value)` and return the new value for that element.
+ ///
+ /// Returns `Error(Nil)` if no the function does not return Ok for any of the
+ /// elements.
+ ///
+ /// ## Examples
+ ///
+ /// > find_map([[], [2], [3]], head)
+ /// Ok(2)
+ ///
+ /// > find_map([[], []], head)
+ /// Error(Nil)
+ ///
+ /// > find_map([], head)
+ /// Error(Nil)
+ ///
+ pub fn find_map(
+ in haystack: List(a),
+ with fun: fn(a) -> Result(b, c),
+ ) -> Result(b, Nil) {
+ case haystack {
+ [] -> Error(Nil)
+ [x, ..rest] ->
+ case fun(x) {
+ Ok(x) -> Ok(x)
+ _ -> find_map(in: rest, with: fun)
+ }
+ }
}
-}
-/// Returns True if the given function returns True for any the elements in
-/// the given list. If the function returns True for any of the elements it
-/// immediately returns True without checking the rest of the list.
-///
-/// ## Examples
-///
-/// > any([], fn(x) { x > 3 })
-/// False
-///
-/// > any([4, 5], fn(x) { x > 3 })
-/// False
-///
-/// > any([4, 3], fn(x) { x > 3 })
-/// True
-///
-/// > any([3, 4], fn(x) { x > 3 })
-/// True
-///
-pub fn any(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool {
- case list {
- [] -> False
- [x, ..rest] -> predicate(x) || any(rest, predicate)
+ /// Returns True if the given function returns True for all the elements in
+ /// the given list. If the function returns False for any of the elements it
+ /// immediately returns False without checking the rest of the list.
+ ///
+ /// ## Examples
+ ///
+ /// > all([], fn(x) { x > 3 })
+ /// True
+ ///
+ /// > all([4, 5], fn(x) { x > 3 })
+ /// True
+ ///
+ /// > all([4, 3], fn(x) { x > 3 })
+ /// False
+ ///
+ pub fn all(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool {
+ case list {
+ [] -> True
+ [x, ..rest] -> predicate(x) && all(rest, predicate)
+ }
}
-}
-fn do_zip(xs: List(a), ys: List(b), acc: List(#(a, b))) -> List(#(a, b)) {
- case xs, ys {
- [x, ..xs], [y, ..ys] -> do_zip(xs, ys, [#(x, y), ..acc])
- _, _ -> reverse(acc)
+ /// Returns True if the given function returns True for any the elements in
+ /// the given list. If the function returns True for any of the elements it
+ /// immediately returns True without checking the rest of the list.
+ ///
+ /// ## Examples
+ ///
+ /// > any([], fn(x) { x > 3 })
+ /// False
+ ///
+ /// > any([4, 5], fn(x) { x > 3 })
+ /// False
+ ///
+ /// > any([4, 3], fn(x) { x > 3 })
+ /// True
+ ///
+ /// > any([3, 4], fn(x) { x > 3 })
+ /// True
+ ///
+ pub fn any(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool {
+ case list {
+ [] -> False
+ [x, ..rest] -> predicate(x) || any(rest, predicate)
+ }
}
-}
-/// Takes two lists and returns a single list of 2 item tuples.
-///
-/// If one of the lists is longer than the other the remaining elements from
-/// the longer list are not used.
-///
-/// ## Examples
-///
-/// > zip([], [])
-/// []
-///
-/// > zip([1, 2], [3])
-/// [#(1, 3)]
-///
-/// > zip([1], [3, 4])
-/// [#(1, 3)]
-///
-/// > zip([1, 2], [3, 4])
-/// [#(1, 3), #(2, 4)]
-///
-pub fn zip(xs: List(a), ys: List(b)) -> List(#(a, b)) {
- do_zip(xs, ys, [])
-}
+ fn do_zip(xs: List(a), ys: List(b), acc: List(#(a, b))) -> List(#(a, b)) {
+ case xs, ys {
+ [x, ..xs], [y, ..ys] -> do_zip(xs, ys, [#(x, y), ..acc])
+ _, _ -> reverse(acc)
+ }
+ }
-/// Takes two lists and returns a single list of 2 item tuples.
-///
-/// If one of the lists is longer than the other an Error is returned.
-///
-/// ## Examples
-///
-/// > strict_zip([], [])
-/// Ok([])
-///
-/// > strict_zip([1, 2], [3])
-/// Error(LengthMismatch)
-///
-/// > strict_zip([1], [3, 4])
-/// Error(LengthMismatch)
-///
-/// > strict_zip([1, 2], [3, 4])
-/// Ok([#(1, 3), #(2, 4)])
-///
-pub fn strict_zip(
- l1: List(a),
- l2: List(b),
-) -> Result(List(#(a, b)), LengthMismatch) {
- case length(of: l1) == length(of: l2) {
- True -> Ok(zip(l1, l2))
- False -> Error(LengthMismatch)
+ /// Takes two lists and returns a single list of 2 item tuples.
+ ///
+ /// If one of the lists is longer than the other the remaining elements from
+ /// the longer list are not used.
+ ///
+ /// ## Examples
+ ///
+ /// > zip([], [])
+ /// []
+ ///
+ /// > zip([1, 2], [3])
+ /// [#(1, 3)]
+ ///
+ /// > zip([1], [3, 4])
+ /// [#(1, 3)]
+ ///
+ /// > zip([1, 2], [3, 4])
+ /// [#(1, 3), #(2, 4)]
+ ///
+ pub fn zip(xs: List(a), ys: List(b)) -> List(#(a, b)) {
+ do_zip(xs, ys, [])
}
-}
-fn do_unzip(input, xs, ys) {
- case input {
- [] -> #(reverse(xs), reverse(ys))
- [#(x, y), ..rest] -> do_unzip(rest, [x, ..xs], [y, ..ys])
+ /// Takes two lists and returns a single list of 2 item tuples.
+ ///
+ /// If one of the lists is longer than the other an Error is returned.
+ ///
+ /// ## Examples
+ ///
+ /// > strict_zip([], [])
+ /// Ok([])
+ ///
+ /// > strict_zip([1, 2], [3])
+ /// Error(LengthMismatch)
+ ///
+ /// > strict_zip([1], [3, 4])
+ /// Error(LengthMismatch)
+ ///
+ /// > strict_zip([1, 2], [3, 4])
+ /// Ok([#(1, 3), #(2, 4)])
+ ///
+ pub fn strict_zip(
+ l1: List(a),
+ l2: List(b),
+ ) -> Result(List(#(a, b)), LengthMismatch) {
+ case length(of: l1) == length(of: l2) {
+ True -> Ok(zip(l1, l2))
+ False -> Error(LengthMismatch)
+ }
}
-}
-/// Takes a single list of 2 item tuples and returns two lists.
-///
-/// ## Examples
-///
-/// > unzip([#(1, 2), #(3, 4)])
-/// #([1, 3], [2, 4])
-///
-/// > unzip([])
-/// #([], [])
-///
-pub fn unzip(input: List(#(a, b))) -> #(List(a), List(b)) {
- do_unzip(input, [], [])
-}
+ fn do_unzip(input, xs, ys) {
+ case input {
+ [] -> #(reverse(xs), reverse(ys))
+ [#(x, y), ..rest] -> do_unzip(rest, [x, ..xs], [y, ..ys])
+ }
+ }
-fn do_intersperse(list: List(a), separator: a, acc: List(a)) -> List(a) {
- case list {
- [] -> reverse(acc)
- [x, ..rest] -> do_intersperse(rest, separator, [x, separator, ..acc])
+ /// Takes a single list of 2 item tuples and returns two lists.
+ ///
+ /// ## Examples
+ ///
+ /// > unzip([#(1, 2), #(3, 4)])
+ /// #([1, 3], [2, 4])
+ ///
+ /// > unzip([])
+ /// #([], [])
+ ///
+ pub fn unzip(input: List(#(a, b))) -> #(List(a), List(b)) {
+ do_unzip(input, [], [])
}
-}
-/// Inserts a given value between each existing element in a given list.
-///
-/// This function runs in linear time and copies the list.
-///
-/// ## Examples
-///
-/// > intersperse([1, 1, 1], 2)
-/// [1, 2, 1, 2, 1]
-///
-/// > intersperse([], 2)
-/// []
-///
-pub fn intersperse(list: List(a), with elem: a) -> List(a) {
- case list {
- [] | [_] -> list
- [x, ..rest] -> do_intersperse(rest, elem, [x])
+ fn do_intersperse(list: List(a), separator: a, acc: List(a)) -> List(a) {
+ case list {
+ [] -> reverse(acc)
+ [x, ..rest] -> do_intersperse(rest, separator, [x, separator, ..acc])
+ }
}
-}
-/// Returns the element in the Nth position in the list, with 0 being the first
-/// position.
-///
-/// Error(Nil) is returned if the list is not long enough for the given index.
-///
-/// ## Examples
-///
-/// > at([1, 2, 3], 1)
-/// Ok(2)
-///
-/// > at([1, 2, 3], 5)
-/// Error(Nil)
-///
-pub fn at(in list: List(a), get index: Int) -> Result(a, Nil) {
- case index < 0 {
- True -> Error(Nil)
- False ->
- case list {
- [] -> Error(Nil)
- [x, ..rest] ->
- case index == 0 {
- True -> Ok(x)
- False -> at(rest, index - 1)
- }
- }
+ /// Inserts a given value between each existing element in a given list.
+ ///
+ /// This function runs in linear time and copies the list.
+ ///
+ /// ## Examples
+ ///
+ /// > intersperse([1, 1, 1], 2)
+ /// [1, 2, 1, 2, 1]
+ ///
+ /// > intersperse([], 2)
+ /// []
+ ///
+ pub fn intersperse(list: List(a), with elem: a) -> List(a) {
+ case list {
+ [] | [_] -> list
+ [x, ..rest] -> do_intersperse(rest, elem, [x])
+ }
}
-}
-/// Removes any duplicate elements from a given list.
-///
-/// This function returns in log-linear time (n log n).
-///
-/// ## Examples
-///
-/// > unique([1, 1, 1, 4, 7, 3, 3, 4])
-/// [1, 4, 7, 3]
-///
-pub fn unique(list: List(a)) -> List(a) {
- case list {
- [] -> []
- [x, ..rest] -> [x, ..unique(filter(rest, fn(y) { y != x }))]
+ /// Returns the element in the Nth position in the list, with 0 being the first
+ /// position.
+ ///
+ /// Error(Nil) is returned if the list is not long enough for the given index.
+ ///
+ /// ## Examples
+ ///
+ /// > at([1, 2, 3], 1)
+ /// Ok(2)
+ ///
+ /// > at([1, 2, 3], 5)
+ /// Error(Nil)
+ ///
+ pub fn at(in list: List(a), get index: Int) -> Result(a, Nil) {
+ case index < 0 {
+ True -> Error(Nil)
+ False ->
+ case list {
+ [] -> Error(Nil)
+ [x, ..rest] ->
+ case index == 0 {
+ True -> Ok(x)
+ False -> at(rest, index - 1)
+ }
+ }
+ }
}
-}
-fn merge_sort(a: List(a), b: List(a), compare: fn(a, a) -> Order) -> List(a) {
- case a, b {
- [], _ -> b
- _, [] -> a
- [ax, ..ar], [bx, ..br] ->
- case compare(ax, bx) {
- order.Lt -> [ax, ..merge_sort(ar, b, compare)]
- _ -> [bx, ..merge_sort(a, br, compare)]
- }
+ /// Removes any duplicate elements from a given list.
+ ///
+ /// This function returns in log-linear time (n log n).
+ ///
+ /// ## Examples
+ ///
+ /// > unique([1, 1, 1, 4, 7, 3, 3, 4])
+ /// [1, 4, 7, 3]
+ ///
+ pub fn unique(list: List(a)) -> List(a) {
+ case list {
+ [] -> []
+ [x, ..rest] -> [x, ..unique(filter(rest, fn(y) { y != x }))]
+ }
}
-}
-fn do_sort(
- list: List(a),
- compare: fn(a, a) -> Order,
- list_length: Int,
-) -> List(a) {
- case list_length < 2 {
- True -> list
- False -> {
- let split_length = list_length / 2
- let a_list = take(list, split_length)
- let b_list = drop(list, split_length)
- merge_sort(
- do_sort(a_list, compare, split_length),
- do_sort(b_list, compare, list_length - split_length),
- compare,
- )
+ fn merge_sort(a: List(a), b: List(a), compare: fn(a, a) -> Order) -> List(a) {
+ case a, b {
+ [], _ -> b
+ _, [] -> a
+ [ax, ..ar], [bx, ..br] ->
+ case compare(ax, bx) {
+ order.Lt -> [ax, ..merge_sort(ar, b, compare)]
+ _ -> [bx, ..merge_sort(a, br, compare)]
+ }
}
}
-}
-/// Sorts from smallest to largest based upon the ordering specified by a given
-/// function.
-///
-/// ## Examples
-///
-/// > import gleam/int
-/// > list.sort([4, 3, 6, 5, 4, 1, 2], by: int.compare)
-/// [1, 2, 3, 4, 4, 5, 6]
-///
-pub fn sort(list: List(a), by compare: fn(a, a) -> Order) -> List(a) {
- do_sort(list, compare, length(list))
-}
+ fn do_sort(
+ list: List(a),
+ compare: fn(a, a) -> Order,
+ list_length: Int,
+ ) -> List(a) {
+ case list_length < 2 {
+ True -> list
+ False -> {
+ let split_length = list_length / 2
+ let a_list = take(list, split_length)
+ let b_list = drop(list, split_length)
+ merge_sort(
+ do_sort(a_list, compare, split_length),
+ do_sort(b_list, compare, list_length - split_length),
+ compare,
+ )
+ }
+ }
+ }
-/// Creates a list of ints ranging from a given start and finish.
-///
-/// ## Examples
-///
-/// > range(0, 0)
-/// []
-///
-/// > range(0, 5)
-/// [0, 1, 2, 3, 4]
-///
-/// > range(1, -5)
-/// [1, 0, -1, -2, -3, -4]
-///
-pub fn range(from start: Int, to stop: Int) -> List(Int) {
- case int.compare(start, stop) {
- order.Eq -> []
- order.Gt -> [start, ..range(start - 1, stop)]
- order.Lt -> [start, ..range(start + 1, stop)]
+ /// Sorts from smallest to largest based upon the ordering specified by a given
+ /// function.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/int
+ /// > list.sort([4, 3, 6, 5, 4, 1, 2], by: int.compare)
+ /// [1, 2, 3, 4, 4, 5, 6]
+ ///
+ pub fn sort(list: List(a), by compare: fn(a, a) -> Order) -> List(a) {
+ do_sort(list, compare, length(list))
}
-}
-fn do_repeat(a: a, times: Int, acc: List(a)) -> List(a) {
- case times <= 0 {
- True -> acc
- False -> do_repeat(a, times - 1, [a, ..acc])
+ /// Creates a list of ints ranging from a given start and finish.
+ ///
+ /// ## Examples
+ ///
+ /// > range(0, 0)
+ /// []
+ ///
+ /// > range(0, 5)
+ /// [0, 1, 2, 3, 4]
+ ///
+ /// > range(1, -5)
+ /// [1, 0, -1, -2, -3, -4]
+ ///
+ pub fn range(from start: Int, to stop: Int) -> List(Int) {
+ case int.compare(start, stop) {
+ order.Eq -> []
+ order.Gt -> [start, ..range(start - 1, stop)]
+ order.Lt -> [start, ..range(start + 1, stop)]
+ }
}
-}
-/// Builds a list of a given value a given number of times.
-///
-/// ## Examples
-///
-/// > repeat("a", times: 0)
-/// []
-///
-/// > repeat("a", times: 5)
-/// ["a", "a", "a", "a", "a"]
-///
-pub fn repeat(item a: a, times times: Int) -> List(a) {
- do_repeat(a, times, [])
-}
+ fn do_repeat(a: a, times: Int, acc: List(a)) -> List(a) {
+ case times <= 0 {
+ True -> acc
+ False -> do_repeat(a, times - 1, [a, ..acc])
+ }
+ }
-fn do_split(list: List(a), n: Int, taken: List(a)) -> #(List(a), List(a)) {
- case n <= 0 {
- True -> #(reverse(taken), list)
- False ->
- case list {
- [] -> #(reverse(taken), [])
- [x, ..xs] -> do_split(xs, n - 1, [x, ..taken])
- }
+ /// Builds a list of a given value a given number of times.
+ ///
+ /// ## Examples
+ ///
+ /// > repeat("a", times: 0)
+ /// []
+ ///
+ /// > repeat("a", times: 5)
+ /// ["a", "a", "a", "a", "a"]
+ ///
+ pub fn repeat(item a: a, times times: Int) -> List(a) {
+ do_repeat(a, times, [])
}
-}
-/// Splits a list in two before the given index.
-///
-/// If the list is not long enough to have the given index the before list will
-/// be the input list, and the after list will be empty.
-///
-/// ## Examples
-///
-/// > split([6, 7, 8, 9], 0)
-/// #([], [6, 7, 8, 9])
-///
-/// > split([6, 7, 8, 9], 2)
-/// #([6, 7], [8, 9])
-///
-/// > split([6, 7, 8, 9], 4)
-/// #([6, 7, 8, 9], [])
-///
-pub fn split(list list: List(a), at index: Int) -> #(List(a), List(a)) {
- do_split(list, index, [])
-}
+ fn do_split(list: List(a), n: Int, taken: List(a)) -> #(List(a), List(a)) {
+ case n <= 0 {
+ True -> #(reverse(taken), list)
+ False ->
+ case list {
+ [] -> #(reverse(taken), [])
+ [x, ..xs] -> do_split(xs, n - 1, [x, ..taken])
+ }
+ }
+ }
-fn do_split_while(
- list: List(a),
- f: fn(a) -> Bool,
- acc: List(a),
-) -> #(List(a), List(a)) {
- case list {
- [] -> #(reverse(acc), [])
- [x, ..xs] ->
- case f(x) {
- False -> #(reverse(acc), list)
- _ -> do_split_while(xs, f, [x, ..acc])
- }
+ /// Splits a list in two before the given index.
+ ///
+ /// If the list is not long enough to have the given index the before list will
+ /// be the input list, and the after list will be empty.
+ ///
+ /// ## Examples
+ ///
+ /// > split([6, 7, 8, 9], 0)
+ /// #([], [6, 7, 8, 9])
+ ///
+ /// > split([6, 7, 8, 9], 2)
+ /// #([6, 7], [8, 9])
+ ///
+ /// > split([6, 7, 8, 9], 4)
+ /// #([6, 7, 8, 9], [])
+ ///
+ pub fn split(list list: List(a), at index: Int) -> #(List(a), List(a)) {
+ do_split(list, index, [])
}
-}
-/// Splits a list in two before the first element that a given function returns
-/// False for.
-///
-/// If the function returns True for all elements the first list will be the
-/// input list, and the second list will be empty.
-///
-/// ## Examples
-///
-/// > split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 })
-/// #([1, 2, 3], [4, 5])
-///
-/// > split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 })
-/// #([1, 2, 3, 4, 5], [])
-///
-pub fn split_while(
- list list: List(a),
- satisfying predicate: fn(a) -> Bool,
-) -> #(List(a), List(a)) {
- do_split_while(list, predicate, [])
-}
+ fn do_split_while(
+ list: List(a),
+ f: fn(a) -> Bool,
+ acc: List(a),
+ ) -> #(List(a), List(a)) {
+ case list {
+ [] -> #(reverse(acc), [])
+ [x, ..xs] ->
+ case f(x) {
+ False -> #(reverse(acc), list)
+ _ -> do_split_while(xs, f, [x, ..acc])
+ }
+ }
+ }
-/// Given a list of 2 element tuples, finds the first tuple that has a given
-/// key as the first element and returns the second element.
-///
-/// If no tuple is found with the given key then `Error(Nil)` is returned.
-///
-/// This function may be useful for interacting with Erlang code where lists of
-/// tuples are common.
-///
-/// ## Examples
-///
-/// > key_find([#("a", 0), #("b", 1)], "a")
-/// Ok(0)
-///
-/// > key_find([#("a", 0), #("b", 1)], "b")
-/// Ok(1)
-///
-/// > key_find([#("a", 0), #("b", 1)], "c")
-/// Error(Nil)
-///
-pub fn key_find(
- in keyword_list: List(#(k, v)),
- find desired_key: k,
-) -> Result(v, Nil) {
- find_map(
- keyword_list,
- fn(keyword) {
- let #(key, value) = keyword
- case key == desired_key {
- True -> Ok(value)
- False -> Error(Nil)
- }
- },
- )
-}
+ /// Splits a list in two before the first element that a given function returns
+ /// False for.
+ ///
+ /// If the function returns True for all elements the first list will be the
+ /// input list, and the second list will be empty.
+ ///
+ /// ## Examples
+ ///
+ /// > split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 })
+ /// #([1, 2, 3], [4, 5])
+ ///
+ /// > split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 })
+ /// #([1, 2, 3, 4, 5], [])
+ ///
+ pub fn split_while(
+ list list: List(a),
+ satisfying predicate: fn(a) -> Bool,
+ ) -> #(List(a), List(a)) {
+ do_split_while(list, predicate, [])
+ }
-fn do_pop(haystack, predicate, checked) {
- case haystack {
- [] -> Error(Nil)
- [x, ..rest] ->
- case predicate(x) {
- True -> Ok(#(x, append(reverse(checked), rest)))
- False -> do_pop(rest, predicate, [x, ..checked])
- }
+ /// Given a list of 2 element tuples, finds the first tuple that has a given
+ /// key as the first element and returns the second element.
+ ///
+ /// If no tuple is found with the given key then `Error(Nil)` is returned.
+ ///
+ /// This function may be useful for interacting with Erlang code where lists of
+ /// tuples are common.
+ ///
+ /// ## Examples
+ ///
+ /// > key_find([#("a", 0), #("b", 1)], "a")
+ /// Ok(0)
+ ///
+ /// > key_find([#("a", 0), #("b", 1)], "b")
+ /// Ok(1)
+ ///
+ /// > key_find([#("a", 0), #("b", 1)], "c")
+ /// Error(Nil)
+ ///
+ pub fn key_find(
+ in keyword_list: List(#(k, v)),
+ find desired_key: k,
+ ) -> Result(v, Nil) {
+ find_map(
+ keyword_list,
+ fn(keyword) {
+ let #(key, value) = keyword
+ case key == desired_key {
+ True -> Ok(value)
+ False -> Error(Nil)
+ }
+ },
+ )
}
-}
-/// Removes the first element in a given list for which the predicate funtion returns `True`.
-///
-/// Returns `Error(Nil)` if no the function does not return True for any of the
-/// elements.
-///
-/// ## Examples
-///
-/// > pop([1, 2, 3], fn(x) { x > 2 })
-/// Ok(#(3, [1, 2]))
-///
-/// > pop([1, 2, 3], fn(x) { x > 4 })
-/// Error(Nil)
-///
-/// > pop([], fn(x) { True })
-/// Error(Nil)
-///
-pub fn pop(
- in haystack: List(a),
- one_that is_desired: fn(a) -> Bool,
-) -> Result(#(a, List(a)), Nil) {
- do_pop(haystack, is_desired, [])
-}
+ fn do_pop(haystack, predicate, checked) {
+ case haystack {
+ [] -> Error(Nil)
+ [x, ..rest] ->
+ case predicate(x) {
+ True -> Ok(#(x, append(reverse(checked), rest)))
+ False -> do_pop(rest, predicate, [x, ..checked])
+ }
+ }
+ }
-fn do_pop_map(haystack, mapper, checked) {
- case haystack {
- [] -> Error(Nil)
- [x, ..rest] ->
- case mapper(x) {
- Ok(y) -> Ok(#(y, append(reverse(checked), rest)))
- Error(_) -> do_pop_map(rest, mapper, [x, ..checked])
- }
+ /// Removes the first element in a given list for which the predicate funtion returns `True`.
+ ///
+ /// Returns `Error(Nil)` if no the function does not return True for any of the
+ /// elements.
+ ///
+ /// ## Examples
+ ///
+ /// > pop([1, 2, 3], fn(x) { x > 2 })
+ /// Ok(#(3, [1, 2]))
+ ///
+ /// > pop([1, 2, 3], fn(x) { x > 4 })
+ /// Error(Nil)
+ ///
+ /// > pop([], fn(x) { True })
+ /// Error(Nil)
+ ///
+ pub fn pop(
+ in haystack: List(a),
+ one_that is_desired: fn(a) -> Bool,
+ ) -> Result(#(a, List(a)), Nil) {
+ do_pop(haystack, is_desired, [])
}
-}
-/// Removes the first element in a given list for which the given function returns
-/// `Ok(new_value)` and return the new value as well as list with the value removed.
-///
-/// Returns `Error(Nil)` if no the function does not return Ok for any of the
-/// elements.
-///
-/// ## Examples
-///
-/// > pop_map([[], [2], [3]], head)
-/// Ok(#(2, [[], [3]]))
-///
-/// > pop_map([[], []], head)
-/// Error(Nil)
-///
-/// > pop_map([], head)
-/// Error(Nil)
-///
-pub fn pop_map(
- in haystack: List(a),
- one_that is_desired: fn(a) -> Result(b, c),
-) -> Result(#(b, List(a)), Nil) {
- do_pop_map(haystack, is_desired, [])
-}
+ fn do_pop_map(haystack, mapper, checked) {
+ case haystack {
+ [] -> Error(Nil)
+ [x, ..rest] ->
+ case mapper(x) {
+ Ok(y) -> Ok(#(y, append(reverse(checked), rest)))
+ Error(_) -> do_pop_map(rest, mapper, [x, ..checked])
+ }
+ }
+ }
-/// Given a list of 2 element tuples, finds the first tuple that has a given
-/// key as the first element. This function will return the second element
-/// of the found tuple and list with tuple removed.
-///
-/// If no tuple is found with the given key then `Error(Nil)` is returned.
-///
-/// ## Examples
-///
-/// > key_pop([#("a", 0), #("b", 1)], "a")
-/// Ok(#(0, [#("b", 1)])
-///
-/// > key_pop([#("a", 0), #("b", 1)], "b")
-/// Ok(#(1, [#("a", 0)])
-///
-/// > key_pop([#("a", 0), #("b", 1)], "c")
-/// Error(Nil)
-///
-pub fn key_pop(
- haystack: List(#(k, v)),
- key: k,
-) -> Result(#(v, List(#(k, v))), Nil) {
- pop_map(
- haystack,
- fn(entry) {
- let #(k, v) = entry
- case k {
- k if k == key -> Ok(v)
- _ -> Error(Nil)
- }
- },
- )
-}
+ /// Removes the first element in a given list for which the given function returns
+ /// `Ok(new_value)` and return the new value as well as list with the value removed.
+ ///
+ /// Returns `Error(Nil)` if no the function does not return Ok for any of the
+ /// elements.
+ ///
+ /// ## Examples
+ ///
+ /// > pop_map([[], [2], [3]], head)
+ /// Ok(#(2, [[], [3]]))
+ ///
+ /// > pop_map([[], []], head)
+ /// Error(Nil)
+ ///
+ /// > pop_map([], head)
+ /// Error(Nil)
+ ///
+ pub fn pop_map(
+ in haystack: List(a),
+ one_that is_desired: fn(a) -> Result(b, c),
+ ) -> Result(#(b, List(a)), Nil) {
+ do_pop_map(haystack, is_desired, [])
+ }
-/// Given a list of 2 element tuples, inserts a key and value into the list.
-///
-/// If there was already a tuple with the key then it is replaced, otherwise it
-/// is added to the end of the list.
-///
-///
-/// ## Examples
-///
-/// > key_set([#(5, 0), #(4, 1)], 4, 100)
-/// [#(5, 0), #(4, 100)]
-///
-/// > key_set([#(5, 0), #(4, 1)], 1, 100)
-/// [#(5, 0), #(4, 1), #(1, 100)]
-///
-pub fn key_set(list: List(#(a, b)), key: a, value: b) -> List(#(a, b)) {
- case list {
- [] -> [#(key, value)]
- [#(k, _), ..rest] if k == key -> [#(key, value), ..rest]
- [first, ..rest] -> [first, ..key_set(rest, key, value)]
+ /// Given a list of 2 element tuples, finds the first tuple that has a given
+ /// key as the first element. This function will return the second element
+ /// of the found tuple and list with tuple removed.
+ ///
+ /// If no tuple is found with the given key then `Error(Nil)` is returned.
+ ///
+ /// ## Examples
+ ///
+ /// > key_pop([#("a", 0), #("b", 1)], "a")
+ /// Ok(#(0, [#("b", 1)])
+ ///
+ /// > key_pop([#("a", 0), #("b", 1)], "b")
+ /// Ok(#(1, [#("a", 0)])
+ ///
+ /// > key_pop([#("a", 0), #("b", 1)], "c")
+ /// Error(Nil)
+ ///
+ pub fn key_pop(
+ haystack: List(#(k, v)),
+ key: k,
+ ) -> Result(#(v, List(#(k, v))), Nil) {
+ pop_map(
+ haystack,
+ fn(entry) {
+ let #(k, v) = entry
+ case k {
+ k if k == key -> Ok(v)
+ _ -> Error(Nil)
+ }
+ },
+ )
}
-}
-/// Calls a function for each element in a list, discarding the results.
-///
-pub fn each(list: List(a), f: fn(a) -> b) -> Nil {
- case list {
- [] -> Nil
- [x, ..xs] -> {
- f(x)
- each(xs, f)
+ /// Given a list of 2 element tuples, inserts a key and value into the list.
+ ///
+ /// If there was already a tuple with the key then it is replaced, otherwise it
+ /// is added to the end of the list.
+ ///
+ ///
+ /// ## Examples
+ ///
+ /// > key_set([#(5, 0), #(4, 1)], 4, 100)
+ /// [#(5, 0), #(4, 100)]
+ ///
+ /// > key_set([#(5, 0), #(4, 1)], 1, 100)
+ /// [#(5, 0), #(4, 1), #(1, 100)]
+ ///
+ pub fn key_set(list: List(#(a, b)), key: a, value: b) -> List(#(a, b)) {
+ case list {
+ [] -> [#(key, value)]
+ [#(k, _), ..rest] if k == key -> [#(key, value), ..rest]
+ [first, ..rest] -> [first, ..key_set(rest, key, value)]
}
}
-}
-fn do_partition(list, categorise, trues, falses) {
- case list {
- [] -> #(reverse(trues), reverse(falses))
- [x, ..xs] ->
- case categorise(x) {
- True -> do_partition(xs, categorise, [x, ..trues], falses)
- False -> do_partition(xs, categorise, trues, [x, ..falses])
+ /// Calls a function for each element in a list, discarding the results.
+ ///
+ pub fn each(list: List(a), f: fn(a) -> b) -> Nil {
+ case list {
+ [] -> Nil
+ [x, ..xs] -> {
+ f(x)
+ each(xs, f)
}
+ }
}
-}
-pub fn partition(
- list: List(a),
- with categorise: fn(a) -> Bool,
-) -> #(List(a), List(a)) {
- do_partition(list, categorise, [], [])
-}
+ fn do_partition(list, categorise, trues, falses) {
+ case list {
+ [] -> #(reverse(trues), reverse(falses))
+ [x, ..xs] ->
+ case categorise(x) {
+ True -> do_partition(xs, categorise, [x, ..trues], falses)
+ False -> do_partition(xs, categorise, trues, [x, ..falses])
+ }
+ }
+ }
-/// Returns all the permutations of a list
-/// All values must be unique
-///
-/// ## Examples
-///
-/// > permutations([1, 2])
-/// [[1, 2], [2, 1]]
-///
-pub fn permutations(l: List(a)) -> List(List(a)) {
- case l {
- [] -> [[]]
- _ ->
- map(
- l,
- fn(x) {
- filter(l, fn(y) { y != x })
- |> permutations
- |> map(append([x], _))
- },
- )
- |> flatten
+ pub fn partition(
+ list: List(a),
+ with categorise: fn(a) -> Bool,
+ ) -> #(List(a), List(a)) {
+ do_partition(list, categorise, [], [])
}
-}
-fn do_window(acc: List(List(a)), l: List(a), n: Int) -> List(List(a)) {
- let window = take(l, n)
+ /// Returns all the permutations of a list
+ /// All values must be unique
+ ///
+ /// ## Examples
+ ///
+ /// > permutations([1, 2])
+ /// [[1, 2], [2, 1]]
+ ///
+ pub fn permutations(l: List(a)) -> List(List(a)) {
+ case l {
+ [] -> [[]]
+ _ ->
+ map(
+ l,
+ fn(x) {
+ filter(l, fn(y) { y != x })
+ |> permutations
+ |> map(append([x], _))
+ },
+ )
+ |> flatten
+ }
+ }
+
+ fn do_window(acc: List(List(a)), l: List(a), n: Int) -> List(List(a)) {
+ let window = take(l, n)
- case length(window) == n {
- True -> do_window([window, ..acc], drop(l, 1), n)
- False -> acc
+ case length(window) == n {
+ True -> do_window([window, ..acc], drop(l, 1), n)
+ False -> acc
+ }
}
-}
-/// Returns a list of sliding window
-///
-/// ## Examples
-///
-/// ```
-/// > window([1,2,3,4,5], 3)
-/// [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
-///
-/// > window([1, 2], 4)
-/// []
-/// ```
-///
-pub fn window(l: List(a), by n: Int) -> List(List(a)) {
- do_window([], l, n)
- |> reverse
-}
+ /// Returns a list of sliding window
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > window([1,2,3,4,5], 3)
+ /// [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
+ ///
+ /// > window([1, 2], 4)
+ /// []
+ /// ```
+ ///
+ pub fn window(l: List(a), by n: Int) -> List(List(a)) {
+ do_window([], l, n)
+ |> reverse
+ }
-/// Returns a list of tuples containing two contiguous elements
-///
-/// ## Examples
-///
-/// ```
-/// > window_by_2([1,2,3,4])
-/// [#(1, 2), #(2, 3), #(3, 4)]
-///
-/// > window_by_2([1])
-/// []
-/// ```
-///
-pub fn window_by_2(l: List(a)) -> List(#(a, a)) {
- zip(l, drop(l, 1))
-}
+ /// Returns a list of tuples containing two contiguous elements
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > window_by_2([1,2,3,4])
+ /// [#(1, 2), #(2, 3), #(3, 4)]
+ ///
+ /// > window_by_2([1])
+ /// []
+ /// ```
+ ///
+ pub fn window_by_2(l: List(a)) -> List(#(a, a)) {
+ zip(l, drop(l, 1))
+ }
-/// Drops the first elements in a given list for which the predicate funtion returns `True`.
-///
-/// ## Examples
-///
-/// > drop_while([1, 2, 3, 4], fun (x) { x < 3 })
-/// [3, 4]
-///
-pub fn drop_while(
- in list: List(a),
- satisfying predicate: fn(a) -> Bool,
-) -> List(a) {
- case list {
- [] -> []
- [x, ..xs] ->
- case predicate(x) {
- True -> drop_while(xs, predicate)
- False -> [x, ..xs]
- }
+ /// Drops the first elements in a given list for which the predicate funtion returns `True`.
+ ///
+ /// ## Examples
+ ///
+ /// > drop_while([1, 2, 3, 4], fun (x) { x < 3 })
+ /// [3, 4]
+ ///
+ pub fn drop_while(
+ in list: List(a),
+ satisfying predicate: fn(a) -> Bool,
+ ) -> List(a) {
+ case list {
+ [] -> []
+ [x, ..xs] ->
+ case predicate(x) {
+ True -> drop_while(xs, predicate)
+ False -> [x, ..xs]
+ }
+ }
}
-}
-fn do_take_while(
- list: List(a),
- predicate: fn(a) -> Bool,
- acc: List(a),
-) -> List(a) {
- case list {
- [] -> reverse(acc)
- [head, ..tail] ->
- case predicate(head) {
- True -> do_take_while(tail, predicate, [head, ..acc])
- False -> reverse(acc)
- }
+ fn do_take_while(
+ list: List(a),
+ predicate: fn(a) -> Bool,
+ acc: List(a),
+ ) -> List(a) {
+ case list {
+ [] -> reverse(acc)
+ [head, ..tail] ->
+ case predicate(head) {
+ True -> do_take_while(tail, predicate, [head, ..acc])
+ False -> reverse(acc)
+ }
+ }
}
-}
-/// Takes the first elements in a given list for which the predicate funtion returns `True`.
-///
-/// ## Examples
-///
-/// > take_while([1, 2, 3, 2, 4], fun (x) { x < 3 })
-/// [1, 2]
-///
-pub fn take_while(
- in list: List(a),
- satisfying predicate: fn(a) -> Bool,
-) -> List(a) {
- do_take_while(list, predicate, [])
-}
+ /// Takes the first elements in a given list for which the predicate funtion returns `True`.
+ ///
+ /// ## Examples
+ ///
+ /// > take_while([1, 2, 3, 2, 4], fun (x) { x < 3 })
+ /// [1, 2]
+ ///
+ pub fn take_while(
+ in list: List(a),
+ satisfying predicate: fn(a) -> Bool,
+ ) -> List(a) {
+ do_take_while(list, predicate, [])
+ }
-fn do_chunk(
- list: List(a),
- f: fn(a) -> key,
- previous_key: key,
- current_chunk: List(a),
- acc: List(List(a)),
-) -> List(List(a)) {
- case list {
- [] -> reverse([reverse(current_chunk), ..acc])
- [head, ..tail] -> {
- let key = f(head)
- case key == previous_key {
- False -> do_chunk(tail, f, key, [head], [reverse(current_chunk), ..acc])
- True -> do_chunk(tail, f, key, [head, ..current_chunk], acc)
+ fn do_chunk(
+ list: List(a),
+ f: fn(a) -> key,
+ previous_key: key,
+ current_chunk: List(a),
+ acc: List(List(a)),
+ ) -> List(List(a)) {
+ case list {
+ [] -> reverse([reverse(current_chunk), ..acc])
+ [head, ..tail] -> {
+ let key = f(head)
+ case key == previous_key {
+ False ->
+ do_chunk(tail, f, key, [head], [reverse(current_chunk), ..acc])
+ True -> do_chunk(tail, f, key, [head, ..current_chunk], acc)
+ }
}
}
}
-}
-/// Returns a list of chunks in which
-/// the result of calling `f` on each element is the same.
-///
-/// ## Examples
-///
-/// > [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 })
-/// [[1], [2, 2], [3], [4, 4, 6], [7, 7]]
-///
-pub fn chunk(in list: List(a), by f: fn(a) -> key) -> List(List(a)) {
- case list {
- [] -> []
- [head, ..tail] -> do_chunk(tail, f, f(head), [head], [])
+ /// Returns a list of chunks in which
+ /// the result of calling `f` on each element is the same.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 })
+ /// [[1], [2, 2], [3], [4, 4, 6], [7, 7]]
+ ///
+ pub fn chunk(in list: List(a), by f: fn(a) -> key) -> List(List(a)) {
+ case list {
+ [] -> []
+ [head, ..tail] -> do_chunk(tail, f, f(head), [head], [])
+ }
}
-}
-fn do_sized_chunk(
- list: List(a),
- count: Int,
- left: Int,
- current_chunk: List(a),
- acc: List(List(a)),
-) -> List(List(a)) {
- case list {
- [] ->
- case current_chunk {
- [] -> reverse(acc)
- remaining -> reverse([reverse(remaining), ..acc])
- }
- [head, ..tail] -> {
- let chunk = [head, ..current_chunk]
- case left > 1 {
- False -> do_sized_chunk(tail, count, count, [], [reverse(chunk), ..acc])
- True -> do_sized_chunk(tail, count, left - 1, chunk, acc)
+ fn do_sized_chunk(
+ list: List(a),
+ count: Int,
+ left: Int,
+ current_chunk: List(a),
+ acc: List(List(a)),
+ ) -> List(List(a)) {
+ case list {
+ [] ->
+ case current_chunk {
+ [] -> reverse(acc)
+ remaining -> reverse([reverse(remaining), ..acc])
+ }
+ [head, ..tail] -> {
+ let chunk = [head, ..current_chunk]
+ case left > 1 {
+ False ->
+ do_sized_chunk(tail, count, count, [], [reverse(chunk), ..acc])
+ True -> do_sized_chunk(tail, count, left - 1, chunk, acc)
+ }
}
}
}
-}
-/// Returns a list of chunks containing `count` elements each.
-///
-/// If the last chunk does not have `count` elements, it is instead
-/// a partial chunk, with less than `count` elements.
-///
-/// For any `count` less than 1 this function behaves as if it was set to 1.
-///
-/// ## Examples
-///
-/// > [1, 2, 3, 4, 5, 6] |> chunk(into: 2)
-/// [[1, 2], [3, 4], [5, 6]]
-///
-/// > [1, 2, 3, 4, 5, 6, 7, 8] |> chunk(into: 3)
-/// [[1, 2, 3], [4, 5, 6], [7, 8]]
-///
-pub fn sized_chunk(in list: List(a), into count: Int) -> List(List(a)) {
- do_sized_chunk(list, count, count, [], [])
-}
+ /// Returns a list of chunks containing `count` elements each.
+ ///
+ /// If the last chunk does not have `count` elements, it is instead
+ /// a partial chunk, with less than `count` elements.
+ ///
+ /// For any `count` less than 1 this function behaves as if it was set to 1.
+ ///
+ /// ## Examples
+ ///
+ /// > [1, 2, 3, 4, 5, 6] |> chunk(into: 2)
+ /// [[1, 2], [3, 4], [5, 6]]
+ ///
+ /// > [1, 2, 3, 4, 5, 6, 7, 8] |> chunk(into: 3)
+ /// [[1, 2, 3], [4, 5, 6], [7, 8]]
+ ///
+ pub fn sized_chunk(in list: List(a), into count: Int) -> List(List(a)) {
+ do_sized_chunk(list, count, count, [], [])
+ }
-/// This function acts similar to fold, but does not take an initial state.
-/// Instead, it starts from the first element in the list
-/// and combines it with each subsequent element in turn using the given function.
-/// The function is called as fun(current_element, accumulator).
-///
-/// Returns `Ok` to indicate a successful run, and `Error` if called on an empty list.
-///
-/// ## Examples
-///
-/// > [] |> reduce(fn(x, y) { x + y })
-/// Error(Nil)
-///
-/// > [1, 2, 3, 4, 5] |> reduce(fn(x, y) { x + y })
-/// Ok(15)
-///
-pub fn reduce(over list: List(a), with fun: fn(a, a) -> a) -> Result(a, Nil) {
- case list {
- [] -> Error(Nil)
- [head, ..tail] ->
- fold(tail, head, fun)
- |> Ok
+ /// This function acts similar to fold, but does not take an initial state.
+ /// Instead, it starts from the first element in the list
+ /// and combines it with each subsequent element in turn using the given function.
+ /// The function is called as fun(current_element, accumulator).
+ ///
+ /// Returns `Ok` to indicate a successful run, and `Error` if called on an empty list.
+ ///
+ /// ## Examples
+ ///
+ /// > [] |> reduce(fn(x, y) { x + y })
+ /// Error(Nil)
+ ///
+ /// > [1, 2, 3, 4, 5] |> reduce(fn(x, y) { x + y })
+ /// Ok(15)
+ ///
+ pub fn reduce(over list: List(a), with fun: fn(a, a) -> a) -> Result(a, Nil) {
+ case list {
+ [] -> Error(Nil)
+ [head, ..tail] ->
+ fold(tail, head, fun)
+ |> Ok
+ }
}
-}
-fn do_scan(
- list: List(a),
- accumulator: b,
- accumulated: List(b),
- fun: fn(a, b) -> b,
-) -> List(b) {
- case list {
- [] -> reverse(accumulated)
- [x, ..xs] -> {
- let next = fun(x, accumulator)
- do_scan(xs, next, [next, ..accumulated], fun)
+ fn do_scan(
+ list: List(a),
+ accumulator: b,
+ accumulated: List(b),
+ fun: fn(a, b) -> b,
+ ) -> List(b) {
+ case list {
+ [] -> reverse(accumulated)
+ [x, ..xs] -> {
+ let next = fun(x, accumulator)
+ do_scan(xs, next, [next, ..accumulated], fun)
+ }
}
}
-}
-/// Similar to `fold`, but yields the state of the accumulator at each stage.
-///
-/// ## Examples
-///
-/// > scan(over: [1, 2, 3], from: 100, with: fn(i, acc) { acc + i })
-/// [101, 103, 106]
-///
-pub fn scan(
- over list: List(a),
- from initial: b,
- with fun: fn(a, b) -> b,
-) -> List(b) {
- do_scan(list, initial, [], fun)
-}
+ /// Similar to `fold`, but yields the state of the accumulator at each stage.
+ ///
+ /// ## Examples
+ ///
+ /// > scan(over: [1, 2, 3], from: 100, with: fn(i, acc) { acc + i })
+ /// [101, 103, 106]
+ ///
+ pub fn scan(
+ over list: List(a),
+ from initial: b,
+ with fun: fn(a, b) -> b,
+ ) -> List(b) {
+ do_scan(list, initial, [], fun)
+ }
-/// Returns the last element in the given list.
-///
-/// Returns `Error(Nil)` if the list is empty.
-///
-/// This function runs in linear time.
-/// For a collection oriented around performant access at either end,
-/// see `gleam/queue.Queue`.
-///
-/// ## Examples
-///
-/// > last([])
-/// Error(Nil)
-///
-/// > last([1, 2, 3, 4, 5])
-/// Ok(5)
-///
-pub fn last(list: List(a)) -> Result(a, Nil) {
- list
- |> reduce(fn(elem, _) { elem })
-}
+ /// Returns the last element in the given list.
+ ///
+ /// Returns `Error(Nil)` if the list is empty.
+ ///
+ /// This function runs in linear time.
+ /// For a collection oriented around performant access at either end,
+ /// see `gleam/queue.Queue`.
+ ///
+ /// ## Examples
+ ///
+ /// > last([])
+ /// Error(Nil)
+ ///
+ /// > last([1, 2, 3, 4, 5])
+ /// Ok(5)
+ ///
+ pub fn last(list: List(a)) -> Result(a, Nil) {
+ list
+ |> reduce(fn(elem, _) { elem })
+ }
-/// Return unique combinations of elements in the list
-///
-/// ## Examples
-///
-/// ```
-/// > combinations([1, 2, 3], 2)
-/// [[1, 2], [1, 3], [2, 3]]
-///
-/// > combinations([1, 2, 3, 4], 3)
-/// [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
-/// ```
-///
-pub fn combinations(items: List(a), by n: Int) -> List(List(a)) {
- case n {
- 0 -> [[]]
- _ ->
- case items {
- [] -> []
- [x, ..xs] -> {
- let first_combinations =
- map(combinations(xs, n - 1), with: fn(com) { [x, ..com] })
- |> reverse
- fold(
- first_combinations,
- combinations(xs, n),
- fn(c, acc) { [c, ..acc] },
- )
+ /// Return unique combinations of elements in the list
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > combinations([1, 2, 3], 2)
+ /// [[1, 2], [1, 3], [2, 3]]
+ ///
+ /// > combinations([1, 2, 3, 4], 3)
+ /// [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
+ /// ```
+ ///
+ pub fn combinations(items: List(a), by n: Int) -> List(List(a)) {
+ case n {
+ 0 -> [[]]
+ _ ->
+ case items {
+ [] -> []
+ [x, ..xs] -> {
+ let first_combinations =
+ map(combinations(xs, n - 1), with: fn(com) { [x, ..com] })
+ |> reverse
+ fold(
+ first_combinations,
+ combinations(xs, n),
+ fn(c, acc) { [c, ..acc] },
+ )
+ }
}
- }
+ }
}
-}
-fn do_combination_pairs(items: List(a)) -> List(List(#(a, a))) {
- case items {
- [] -> []
- [x, ..xs] -> {
- let first_combinations = map(xs, with: fn(other) { #(x, other) })
- [first_combinations, ..do_combination_pairs(xs)]
+ fn do_combination_pairs(items: List(a)) -> List(List(#(a, a))) {
+ case items {
+ [] -> []
+ [x, ..xs] -> {
+ let first_combinations = map(xs, with: fn(other) { #(x, other) })
+ [first_combinations, ..do_combination_pairs(xs)]
+ }
}
}
-}
-/// Return unique pair combinations of elements in the list
-///
-/// ## Examples
-///
-/// ```
-/// > combination_pairs([1, 2, 3])
-/// [#(1, 2), #(1, 3), #(2, 3)]
-/// ```
-///
-pub fn combination_pairs(items: List(a)) -> List(#(a, a)) {
- do_combination_pairs(items)
- |> flatten
-}
+ /// Return unique pair combinations of elements in the list
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > combination_pairs([1, 2, 3])
+ /// [#(1, 2), #(1, 3), #(2, 3)]
+ /// ```
+ ///
+ pub fn combination_pairs(items: List(a)) -> List(#(a, a)) {
+ do_combination_pairs(items)
+ |> flatten
+ }
-/// Make a list alternating the elements from the given lists
-///
-/// ## Examples
-///
-/// ```
-/// > list.interleave([[1, 2], [101, 102], [201, 202]])
-/// [1, 101, 201, 2, 102, 202]
-/// ```
-///
-pub fn interleave(list: List(List(a))) -> List(a) {
- transpose(list)
- |> flatten
-}
+ /// Make a list alternating the elements from the given lists
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > list.interleave([[1, 2], [101, 102], [201, 202]])
+ /// [1, 101, 201, 2, 102, 202]
+ /// ```
+ ///
+ pub fn interleave(list: List(List(a))) -> List(a) {
+ transpose(list)
+ |> flatten
+ }
-/// Transpose rows and columns of the list of lists.
-///
-/// ## Examples
-///
-/// ```
-/// > transpose([[1, 2, 3], [101, 102, 103]])
-/// [[1, 101], [2, 102], [3, 103]]
-/// ```
-pub fn transpose(list_of_list: List(List(a))) -> List(List(a)) {
- let take_first = fn(list) {
- case list {
- [] -> []
- [f] -> [f]
- [f, .._rest] -> [f]
+ /// Transpose rows and columns of the list of lists.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > transpose([[1, 2, 3], [101, 102, 103]])
+ /// [[1, 101], [2, 102], [3, 103]]
+ /// ```
+ pub fn transpose(list_of_list: List(List(a))) -> List(List(a)) {
+ let take_first = fn(list) {
+ case list {
+ [] -> []
+ [f] -> [f]
+ [f, .._rest] -> [f]
+ }
}
- }
- case list_of_list {
- [] -> []
- [[], ..xss] -> transpose(xss)
- rows -> {
- let firsts =
- rows
- |> map(take_first)
- |> flatten
- let rest = transpose(map(rows, drop(_, 1)))
- [firsts, ..rest]
+ case list_of_list {
+ [] -> []
+ [[], ..xss] -> transpose(xss)
+ rows -> {
+ let firsts =
+ rows
+ |> map(take_first)
+ |> flatten
+ let rest = transpose(map(rows, drop(_, 1)))
+ [firsts, ..rest]
+ }
}
}
}
diff --git a/src/gleam/map.gleam b/src/gleam/map.gleam
index d51a78e..ff8281d 100644
--- a/src/gleam/map.gleam
+++ b/src/gleam/map.gleam
@@ -1,321 +1,327 @@
-import gleam/result
-import gleam/list
+if erlang {
+ import gleam/result
+ import gleam/list
-/// A dictionary of keys and values.
-///
-/// Any type can be used for the keys and values of a map, but all the keys
-/// must be of the same type and all the values must be of the same type.
-///
-/// Each key can only be present in a map once.
-///
-/// Maps are not ordered in any way, and any unintentional ordering is not to
-/// be relied upon in your code as it may change in future versions of Erlang
-/// or Gleam.
-///
-/// See [the Erlang map module](https://erlang.org/doc/man/maps.html) for more
-/// information.
-///
-pub external type Map(key, value)
+ /// A dictionary of keys and values.
+ ///
+ /// Any type can be used for the keys and values of a map, but all the keys
+ /// must be of the same type and all the values must be of the same type.
+ ///
+ /// Each key can only be present in a map once.
+ ///
+ /// Maps are not ordered in any way, and any unintentional ordering is not to
+ /// be relied upon in your code as it may change in future versions of Erlang
+ /// or Gleam.
+ ///
+ /// See [the Erlang map module](https://erlang.org/doc/man/maps.html) for more
+ /// information.
+ ///
+ pub external type Map(key, value)
-/// Determines the number of key-value pairs in the map.
-/// This function runs in constant time and does not need to iterate the map.
-///
-/// ## Examples
-///
-/// > new() |> size()
-/// 0
-///
-/// > new() |> insert("key", "value") |> size()
-/// 1
-///
-///
-pub external fn size(Map(k, v)) -> Int =
- "maps" "size"
+ /// Determines the number of key-value pairs in the map.
+ /// This function runs in constant time and does not need to iterate the map.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> size()
+ /// 0
+ ///
+ /// > new() |> insert("key", "value") |> size()
+ /// 1
+ ///
+ ///
+ pub external fn size(Map(k, v)) -> Int =
+ "maps" "size"
-/// Converts the map to a list of 2-element tuples `#(key, value)`, one for
-/// each key-value pair in the map.
-///
-/// The tuples in the list have no specific order.
-///
-/// ## Examples
-///
-/// > new() |> to_list()
-/// []
-///
-/// > new() |> insert("key", 0) |> to_list()
-/// [#("key", 0)]
-///
-pub external fn to_list(Map(key, value)) -> List(#(key, value)) =
- "maps" "to_list"
+ /// Converts the map to a list of 2-element tuples `#(key, value)`, one for
+ /// each key-value pair in the map.
+ ///
+ /// The tuples in the list have no specific order.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> to_list()
+ /// []
+ ///
+ /// > new() |> insert("key", 0) |> to_list()
+ /// [#("key", 0)]
+ ///
+ pub external fn to_list(Map(key, value)) -> List(#(key, value)) =
+ "maps" "to_list"
-/// Converts a list of 2-element tuples `#(key, value)` to a map.
-///
-/// If two tuples have the same key the last one in the list will be the one
-/// that is present in the map.
-///
-pub external fn from_list(List(#(key, value))) -> Map(key, value) =
- "maps" "from_list"
+ /// Converts a list of 2-element tuples `#(key, value)` to a map.
+ ///
+ /// If two tuples have the same key the last one in the list will be the one
+ /// that is present in the map.
+ ///
+ pub external fn from_list(List(#(key, value))) -> Map(key, value) =
+ "maps" "from_list"
-external fn is_key(key, Map(key, v)) -> Bool =
- "maps" "is_key"
+ external fn is_key(key, Map(key, v)) -> Bool =
+ "maps" "is_key"
-/// Determines whether or not a value present in the map for a given key.
-///
-/// ## Examples
-///
-/// > new() |> insert("a", 0) |> has_key("a")
-/// True
-///
-/// > new() |> insert("a", 0) |> has_key("b")
-/// False
-///
-pub fn has_key(map: Map(k, v), key: k) -> Bool {
- is_key(key, map)
-}
+ /// Determines whether or not a value present in the map for a given key.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> insert("a", 0) |> has_key("a")
+ /// True
+ ///
+ /// > new() |> insert("a", 0) |> has_key("b")
+ /// False
+ ///
+ pub fn has_key(map: Map(k, v), key: k) -> Bool {
+ is_key(key, map)
+ }
-/// Creates a fresh map that contains no values.
-///
-pub external fn new() -> Map(key, value) =
- "maps" "new"
+ /// Creates a fresh map that contains no values.
+ ///
+ pub external fn new() -> Map(key, value) =
+ "maps" "new"
-/// Fetches a value from a map for a given key.
-///
-/// The map may not have a value for the key, so the value is wrapped in a
-/// Result.
-///
-/// ## Examples
-///
-/// > new() |> insert("a", 0) |> get("a")
-/// Ok(0)
-///
-/// > new() |> insert("a", 0) |> get("b")
-/// Error(Nil)
-///
-pub external fn get(from: Map(key, value), get: key) -> Result(value, Nil) =
- "gleam_stdlib" "map_get"
+ /// Fetches a value from a map for a given key.
+ ///
+ /// The map may not have a value for the key, so the value is wrapped in a
+ /// Result.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> insert("a", 0) |> get("a")
+ /// Ok(0)
+ ///
+ /// > new() |> insert("a", 0) |> get("b")
+ /// Error(Nil)
+ ///
+ pub external fn get(from: Map(key, value), get: key) -> Result(value, Nil) =
+ "gleam_stdlib" "map_get"
-external fn erl_insert(key, value, Map(key, value)) -> Map(key, value) =
- "maps" "put"
+ external fn erl_insert(key, value, Map(key, value)) -> Map(key, value) =
+ "maps" "put"
-/// Inserts a value into the map with the given key.
-///
-/// If the map already has a value for the given key then the value is
-/// replaced with the new value.
-///
-/// ## Examples
-///
-/// > new() |> insert("a", 0) |> to_list
-/// [#("a", 0)]
-///
-/// > new() |> insert("a", 0) |> insert("a", 5) |> to_list
-/// [#("a", 5)]
-///
-pub fn insert(into map: Map(k, v), for key: k, insert value: v) -> Map(k, v) {
- erl_insert(key, value, map)
-}
+ /// Inserts a value into the map with the given key.
+ ///
+ /// If the map already has a value for the given key then the value is
+ /// replaced with the new value.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> insert("a", 0) |> to_list
+ /// [#("a", 0)]
+ ///
+ /// > new() |> insert("a", 0) |> insert("a", 5) |> to_list
+ /// [#("a", 5)]
+ ///
+ pub fn insert(into map: Map(k, v), for key: k, insert value: v) -> Map(k, v) {
+ erl_insert(key, value, map)
+ }
-external fn erl_map_values(fn(key, a) -> b, Map(key, value)) -> Map(key, b) =
- "maps" "map"
+ external fn erl_map_values(fn(key, a) -> b, Map(key, value)) -> Map(key, b) =
+ "maps" "map"
-/// Updates all values in a given map by calling a given function on each key
-/// and value.
-///
-/// ## Examples
-///
-/// > [#(3, 3), #(2, 4)]
-/// > |> from_list
-/// > |> map_values(fn(key, value) { key * value })
-/// [#(3, 9), #(2, 8)]
-///
-///
-pub fn map_values(in map: Map(k, v), with fun: fn(k, v) -> w) -> Map(k, w) {
- erl_map_values(fun, map)
-}
+ /// Updates all values in a given map by calling a given function on each key
+ /// and value.
+ ///
+ /// ## Examples
+ ///
+ /// > [#(3, 3), #(2, 4)]
+ /// > |> from_list
+ /// > |> map_values(fn(key, value) { key * value })
+ /// [#(3, 9), #(2, 8)]
+ ///
+ ///
+ pub fn map_values(in map: Map(k, v), with fun: fn(k, v) -> w) -> Map(k, w) {
+ erl_map_values(fun, map)
+ }
-/// Gets a list of all keys in a given map.
-///
-/// Maps are not ordered so the keys are not returned in any specific order. Do
-/// not write code that relies on the order keys are returned by this function
-/// as it may change in later versions of Gleam or Erlang.
-///
-/// ## Examples
-///
-/// > keys([#("a", 0), #("b", 1)])
-/// ["a", "b"]
-///
-pub external fn keys(Map(keys, v)) -> List(keys) =
- "maps" "keys"
+ /// Gets a list of all keys in a given map.
+ ///
+ /// Maps are not ordered so the keys are not returned in any specific order. Do
+ /// not write code that relies on the order keys are returned by this function
+ /// as it may change in later versions of Gleam or Erlang.
+ ///
+ /// ## Examples
+ ///
+ /// > keys([#("a", 0), #("b", 1)])
+ /// ["a", "b"]
+ ///
+ pub external fn keys(Map(keys, v)) -> List(keys) =
+ "maps" "keys"
-/// Gets a list of all values in a given map.
-///
-/// Maps are not ordered so the values are not returned in any specific order. Do
-/// not write code that relies on the order values are returned by this function
-/// as it may change in later versions of Gleam or Erlang.
-///
-/// ## Examples
-///
-/// > keys(from_list([#("a", 0), #("b", 1)]))
-/// [0, 1]
-///
-pub external fn values(Map(k, values)) -> List(values) =
- "maps" "values"
+ /// Gets a list of all values in a given map.
+ ///
+ /// Maps are not ordered so the values are not returned in any specific order. Do
+ /// not write code that relies on the order values are returned by this function
+ /// as it may change in later versions of Gleam or Erlang.
+ ///
+ /// ## Examples
+ ///
+ /// > keys(from_list([#("a", 0), #("b", 1)]))
+ /// [0, 1]
+ ///
+ pub external fn values(Map(k, values)) -> List(values) =
+ "maps" "values"
-external fn erl_filter(
- fn(key, value) -> Bool,
- Map(key, value),
-) -> Map(key, value) =
- "maps" "filter"
+ external fn erl_filter(
+ fn(key, value) -> Bool,
+ Map(key, value),
+ ) -> Map(key, value) =
+ "maps" "filter"
-/// Creates a new map from a given map, minus any entries that a given function
-/// returns False for.
-///
-/// ## Examples
-///
-/// > from_list([#("a", 0), #("b", 1)])
-/// > |> filter(fn(key, value) { value != 0 })
-/// from_list([#("b", 1)])
-///
-/// > from_list([#("a", 0), #("b", 1)])
-/// > |> filter(fn(key, value) { True })
-/// from_list([#("a", 0), #("b", 1)])
-///
-pub fn filter(in map: Map(k, v), for property: fn(k, v) -> Bool) -> Map(k, v) {
- erl_filter(property, map)
-}
+ /// Creates a new map from a given map, minus any entries that a given function
+ /// returns False for.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([#("a", 0), #("b", 1)])
+ /// > |> filter(fn(key, value) { value != 0 })
+ /// from_list([#("b", 1)])
+ ///
+ /// > from_list([#("a", 0), #("b", 1)])
+ /// > |> filter(fn(key, value) { True })
+ /// from_list([#("a", 0), #("b", 1)])
+ ///
+ pub fn filter(in map: Map(k, v), for property: fn(k, v) -> Bool) -> Map(k, v) {
+ erl_filter(property, map)
+ }
-external fn erl_take(List(k), Map(k, v)) -> Map(k, v) =
- "maps" "with"
+ external fn erl_take(List(k), Map(k, v)) -> Map(k, v) =
+ "maps" "with"
-/// Creates a new map from a given map, only including any entries for which the
-/// keys are in a given list.
-///
-/// ## Examples
-///
-/// > from_list([#("a", 0), #("b", 1)])
-/// > |> take(["b"])
-/// from_list([#("b", 1)])
-///
-/// > from_list([#("a", 0), #("b", 1)])
-/// > |> take(["a", "b", "c"])
-/// from_list([#("a", 0), #("b", 1)])
-///
-pub fn take(from map: Map(k, v), keeping desired_keys: List(k)) -> Map(k, v) {
- erl_take(desired_keys, map)
-}
+ /// Creates a new map from a given map, only including any entries for which the
+ /// keys are in a given list.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([#("a", 0), #("b", 1)])
+ /// > |> take(["b"])
+ /// from_list([#("b", 1)])
+ ///
+ /// > from_list([#("a", 0), #("b", 1)])
+ /// > |> take(["a", "b", "c"])
+ /// from_list([#("a", 0), #("b", 1)])
+ ///
+ pub fn take(from map: Map(k, v), keeping desired_keys: List(k)) -> Map(k, v) {
+ erl_take(desired_keys, map)
+ }
-/// Creates a new map from a pair of given maps by combining their entries.
-///
-/// If there are entries with the same keys in both maps the entry from the
-/// second map takes precedence.
-///
-/// ## Examples
-///
-/// > let a = from_list([#("a", 0), #("b", 1)])
-/// > let b = from_list([#("b", 2), #("c", 3)])
-/// > merge(a, b)
-/// from_list([#("a", 0), #("b", 2), #("c", 3)])
-///
-pub external fn merge(into: Map(k, v), merge: Map(k, v)) -> Map(k, v) =
- "maps" "merge"
+ /// Creates a new map from a pair of given maps by combining their entries.
+ ///
+ /// If there are entries with the same keys in both maps the entry from the
+ /// second map takes precedence.
+ ///
+ /// ## Examples
+ ///
+ /// > let a = from_list([#("a", 0), #("b", 1)])
+ /// > let b = from_list([#("b", 2), #("c", 3)])
+ /// > merge(a, b)
+ /// from_list([#("a", 0), #("b", 2), #("c", 3)])
+ ///
+ pub external fn merge(into: Map(k, v), merge: Map(k, v)) -> Map(k, v) =
+ "maps" "merge"
-external fn erl_delete(k, Map(k, v)) -> Map(k, v) =
- "maps" "remove"
+ external fn erl_delete(k, Map(k, v)) -> Map(k, v) =
+ "maps" "remove"
-/// Creates a new map from a given map with all the same entries except for the
-/// one with a given key, if it exists.
-///
-/// ## Examples
-///
-/// > delete([#("a", 0), #("b", 1)], "a")
-/// from_list([#("b", 1)])
-///
-/// > delete([#("a", 0), #("b", 1)], "c")
-/// from_list([#("a", 0), #("b", 1)])
-///
-pub fn delete(from map: Map(k, v), delete key: k) -> Map(k, v) {
- erl_delete(key, map)
-}
+ /// Creates a new map from a given map with all the same entries except for the
+ /// one with a given key, if it exists.
+ ///
+ /// ## Examples
+ ///
+ /// > delete([#("a", 0), #("b", 1)], "a")
+ /// from_list([#("b", 1)])
+ ///
+ /// > delete([#("a", 0), #("b", 1)], "c")
+ /// from_list([#("a", 0), #("b", 1)])
+ ///
+ pub fn delete(from map: Map(k, v), delete key: k) -> Map(k, v) {
+ erl_delete(key, map)
+ }
-/// Creates a new map from a given map with all the same entries except any with
-/// keys found in a given list.
-///
-/// ## Examples
-///
-/// > drop([#("a", 0), #("b", 1)], ["a"])
-/// from_list([#("b", 2)])
-///
-/// > delete([#("a", 0), #("b", 1)], ["c"])
-/// from_list([#("a", 0), #("b", 1)])
-///
-/// > drop([#("a", 0), #("b", 1)], ["a", "b", "c"])
-/// from_list([])
-///
-pub fn drop(from map: Map(k, v), drop disallowed_keys: List(k)) -> Map(k, v) {
- list.fold(disallowed_keys, map, fn(key, acc) { delete(acc, key) })
-}
+ /// Creates a new map from a given map with all the same entries except any with
+ /// keys found in a given list.
+ ///
+ /// ## Examples
+ ///
+ /// > drop([#("a", 0), #("b", 1)], ["a"])
+ /// from_list([#("b", 2)])
+ ///
+ /// > delete([#("a", 0), #("b", 1)], ["c"])
+ /// from_list([#("a", 0), #("b", 1)])
+ ///
+ /// > drop([#("a", 0), #("b", 1)], ["a", "b", "c"])
+ /// from_list([])
+ ///
+ pub fn drop(from map: Map(k, v), drop disallowed_keys: List(k)) -> Map(k, v) {
+ list.fold(disallowed_keys, map, fn(key, acc) { delete(acc, key) })
+ }
-/// Creates a new map with one entry updated using a given function.
-///
-/// If there was not an entry in the map for the given key then the function
-/// gets `Error(Nil)` as its argument, otherwise it gets `Ok(value)`.
-///
-/// ## Example
-///
-/// > let increment = fn(x) {
-/// > case x {
-/// > Ok(i) -> i + 1
-/// > Error(Nil) -> 0
-/// > }
-/// > }
-/// > let map = from_list([#("a", 0)])
-/// >
-/// > update(map, "a" increment)
-/// from_list([#("a", 1)])
-///
-/// > update(map, "b" increment)
-/// from_list([#("a", 0), #("b", 0)])
-///
-pub fn update(
- in map: Map(k, v),
- update key: k,
- with fun: fn(Result(v, Nil)) -> v,
-) -> Map(k, v) {
- map
- |> get(key)
- |> fun
- |> insert(map, key, _)
-}
+ /// Creates a new map with one entry updated using a given function.
+ ///
+ /// If there was not an entry in the map for the given key then the function
+ /// gets `Error(Nil)` as its argument, otherwise it gets `Ok(value)`.
+ ///
+ /// ## Example
+ ///
+ /// > let increment = fn(x) {
+ /// > case x {
+ /// > Ok(i) -> i + 1
+ /// > Error(Nil) -> 0
+ /// > }
+ /// > }
+ /// > let map = from_list([#("a", 0)])
+ /// >
+ /// > update(map, "a" increment)
+ /// from_list([#("a", 1)])
+ ///
+ /// > update(map, "b" increment)
+ /// from_list([#("a", 0), #("b", 0)])
+ ///
+ pub fn update(
+ in map: Map(k, v),
+ update key: k,
+ with fun: fn(Result(v, Nil)) -> v,
+ ) -> Map(k, v) {
+ map
+ |> get(key)
+ |> fun
+ |> insert(map, key, _)
+ }
-fn do_fold(list: List(#(k, v)), initial: acc, fun: fn(k, v, acc) -> acc) -> acc {
- case list {
- [] -> initial
- [#(k, v), ..tail] -> do_fold(tail, fun(k, v, initial), fun)
+ fn do_fold(
+ list: List(#(k, v)),
+ initial: acc,
+ fun: fn(k, v, acc) -> acc,
+ ) -> acc {
+ case list {
+ [] -> initial
+ [#(k, v), ..tail] -> do_fold(tail, fun(k, v, initial), fun)
+ }
}
-}
-/// Combines all entries into a single value by calling a given function on each
-/// one.
-///
-/// Maps are not ordered so the values are not returned in any specific order. Do
-/// not write code that relies on the order entries are used by this function
-/// as it may change in later versions of Gleam or Erlang.
-///
-/// # Examples
-///
-/// > let map = from_list([#("a", 1), #("b", 3), #("c", 9)])
-/// > fold(map, 0, fn(key, value, accumulator) { accumulator + value })
-/// 13
-///
-/// > import gleam/string.{append}
-/// > fold(map, "", fn(key, value, accumulator) { append(accumulator, value) })
-/// "abc"
-///
-pub fn fold(
- over map: Map(k, v),
- from initial: acc,
- with fun: fn(k, v, acc) -> acc,
-) -> acc {
- map
- |> to_list
- |> do_fold(initial, fun)
+ /// Combines all entries into a single value by calling a given function on each
+ /// one.
+ ///
+ /// Maps are not ordered so the values are not returned in any specific order. Do
+ /// not write code that relies on the order entries are used by this function
+ /// as it may change in later versions of Gleam or Erlang.
+ ///
+ /// # Examples
+ ///
+ /// > let map = from_list([#("a", 1), #("b", 3), #("c", 9)])
+ /// > fold(map, 0, fn(key, value, accumulator) { accumulator + value })
+ /// 13
+ ///
+ /// > import gleam/string.{append}
+ /// > fold(map, "", fn(key, value, accumulator) { append(accumulator, value) })
+ /// "abc"
+ ///
+ pub fn fold(
+ over map: Map(k, v),
+ from initial: acc,
+ with fun: fn(k, v, acc) -> acc,
+ ) -> acc {
+ map
+ |> to_list
+ |> do_fold(initial, fun)
+ }
}
diff --git a/src/gleam/option.gleam b/src/gleam/option.gleam
index f72f552..feb6f56 100644
--- a/src/gleam/option.gleam
+++ b/src/gleam/option.gleam
@@ -1,225 +1,227 @@
-import gleam/list
+if erlang {
+ import gleam/list
-/// Option represents a value that may be present or not. Some means the value is
-/// present, None means the value is not.
-///
-/// This is Gleam's alternative to having a value that could be Null, as is
-/// possible in some other languages.
-///
-pub type Option(a) {
- Some(a)
- None
-}
+ /// Option represents a value that may be present or not. Some means the value is
+ /// present, None means the value is not.
+ ///
+ /// This is Gleam's alternative to having a value that could be Null, as is
+ /// possible in some other languages.
+ ///
+ pub type Option(a) {
+ Some(a)
+ None
+ }
-/// Combines a list of options into a single option.
-/// If all elements in the list are Some then returns a Some holding the list of values.
-/// If any element is None then returns None.
-///
-/// ## Examples
-///
-/// ```
-/// > all([Some(1), Some(2)])
-/// Some([1, 2])
-///
-/// > all([Some(1), None])
-/// None
-/// ```
-///
-pub fn all(list: List(Option(a))) -> Option(List(a)) {
- list.fold_right(
- list,
- from: Some([]),
- with: fn(item, acc) {
- case acc, item {
- Some(values), Some(value) -> Some([value, ..values])
- _, _ -> None
- }
- },
- )
-}
+ /// Combines a list of options into a single option.
+ /// If all elements in the list are Some then returns a Some holding the list of values.
+ /// If any element is None then returns None.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > all([Some(1), Some(2)])
+ /// Some([1, 2])
+ ///
+ /// > all([Some(1), None])
+ /// None
+ /// ```
+ ///
+ pub fn all(list: List(Option(a))) -> Option(List(a)) {
+ list.fold_right(
+ list,
+ from: Some([]),
+ with: fn(item, acc) {
+ case acc, item {
+ Some(values), Some(value) -> Some([value, ..values])
+ _, _ -> None
+ }
+ },
+ )
+ }
-/// Checks whether the option is a Some value.
-///
-/// ## Examples
-///
-/// > is_some(Some(1))
-/// True
-///
-/// > is_some(None)
-/// False
-///
-pub fn is_some(option: Option(a)) -> Bool {
- option != None
-}
+ /// Checks whether the option is a Some value.
+ ///
+ /// ## Examples
+ ///
+ /// > is_some(Some(1))
+ /// True
+ ///
+ /// > is_some(None)
+ /// False
+ ///
+ pub fn is_some(option: Option(a)) -> Bool {
+ option != None
+ }
-/// Checks whether the option is a None value.
-///
-/// ## Examples
-///
-/// > is_none(Some(1))
-/// False
-///
-/// > is_none(None)
-/// True
-///
-pub fn is_none(option: Option(a)) -> Bool {
- option == None
-}
+ /// Checks whether the option is a None value.
+ ///
+ /// ## Examples
+ ///
+ /// > is_none(Some(1))
+ /// False
+ ///
+ /// > is_none(None)
+ /// True
+ ///
+ pub fn is_none(option: Option(a)) -> Bool {
+ option == None
+ }
-/// Converts an Option type to a Result type
-///
-/// ## Examples
-///
-/// > to_result(Some(1), "some_error")
-/// Ok(1)
-/// > to_result(None, "some_error")
-/// Error("some_error")
-///
-pub fn to_result(option: Option(a), e) -> Result(a, e) {
- case option {
- Some(a) -> Ok(a)
- _ -> Error(e)
+ /// Converts an Option type to a Result type
+ ///
+ /// ## Examples
+ ///
+ /// > to_result(Some(1), "some_error")
+ /// Ok(1)
+ /// > to_result(None, "some_error")
+ /// Error("some_error")
+ ///
+ pub fn to_result(option: Option(a), e) -> Result(a, e) {
+ case option {
+ Some(a) -> Ok(a)
+ _ -> Error(e)
+ }
}
-}
-/// Converts a Result type to an Option type
-///
-/// ## Examples
-///
-/// > from_result(Ok(1))
-/// Some(1)
-/// > from_result(Error"some_error"))
-/// None
-///
-pub fn from_result(result: Result(a, e)) -> Option(a) {
- case result {
- Ok(a) -> Some(a)
- _ -> None
+ /// Converts a Result type to an Option type
+ ///
+ /// ## Examples
+ ///
+ /// > from_result(Ok(1))
+ /// Some(1)
+ /// > from_result(Error"some_error"))
+ /// None
+ ///
+ pub fn from_result(result: Result(a, e)) -> Option(a) {
+ case result {
+ Ok(a) -> Some(a)
+ _ -> None
+ }
}
-}
-/// Extracts the value from an option, returning a default value if there is none.
-///
-/// ## Examples
-///
-/// > unwrap(Some(1), 0)
-/// 1
-///
-/// > unwrap(None, 0)
-/// 0
-///
-pub fn unwrap(option: Option(a), or default: a) -> a {
- case option {
- Some(x) -> x
- None -> default
+ /// Extracts the value from an option, returning a default value if there is none.
+ ///
+ /// ## Examples
+ ///
+ /// > unwrap(Some(1), 0)
+ /// 1
+ ///
+ /// > unwrap(None, 0)
+ /// 0
+ ///
+ pub fn unwrap(option: Option(a), or default: a) -> a {
+ case option {
+ Some(x) -> x
+ None -> default
+ }
}
-}
-/// Updates a value held within the Some of an Option by calling a given function
-/// on it.
-///
-/// If the option is a None rather than Some the function is not called and the
-/// option stays the same.
-///
-/// ## Examples
-///
-/// > map(over: Some(1), with: fn(x) { x + 1 })
-/// Some(2)
-///
-/// > map(over: None, with: fn(x) { x + 1 })
-/// None
-///
-pub fn map(over option: Option(a), with fun: fn(a) -> b) -> Option(b) {
- case option {
- Some(x) -> Some(fun(x))
- None -> None
+ /// Updates a value held within the Some of an Option by calling a given function
+ /// on it.
+ ///
+ /// If the option is a None rather than Some the function is not called and the
+ /// option stays the same.
+ ///
+ /// ## Examples
+ ///
+ /// > map(over: Some(1), with: fn(x) { x + 1 })
+ /// Some(2)
+ ///
+ /// > map(over: None, with: fn(x) { x + 1 })
+ /// None
+ ///
+ pub fn map(over option: Option(a), with fun: fn(a) -> b) -> Option(b) {
+ case option {
+ Some(x) -> Some(fun(x))
+ None -> None
+ }
}
-}
-/// Merges a nested Option into a single layer.
-///
-/// ## Examples
-///
-/// > flatten(Some(Some(1)))
-/// Some(1)
-///
-/// > flatten(Some(None))
-/// None
-///
-/// > flatten(None)
-/// None
-///
-pub fn flatten(option: Option(Option(a))) -> Option(a) {
- case option {
- Some(x) -> x
- None -> None
+ /// Merges a nested Option into a single layer.
+ ///
+ /// ## Examples
+ ///
+ /// > flatten(Some(Some(1)))
+ /// Some(1)
+ ///
+ /// > flatten(Some(None))
+ /// None
+ ///
+ /// > flatten(None)
+ /// None
+ ///
+ pub fn flatten(option: Option(Option(a))) -> Option(a) {
+ case option {
+ Some(x) -> x
+ None -> None
+ }
}
-}
-/// Updates a value held within the Some of an Option by calling a given function
-/// on it, where the given function also returns an Option. The two Options are
-/// then merged together into one Option.
-///
-/// If the Option is a None rather than Some the function is not called and the
-/// Option stays the same.
-///
-/// This function is the equivalent of calling `map` followed by `flatten`, and
-/// it is useful for chaining together multiple functions that return Options.
-///
-/// ## Examples
-///
-/// > then(Some(1), fn(x) { Some(x + 1) })
-/// Some(2)
-///
-/// > then(Some(1), fn(x) { Some(#("a", x)) })
-/// Some(#("a", 1))
-///
-/// > then(Some(1), fn(x) { None })
-/// None
-///
-/// > then(None, fn(x) { Some(x + 1) })
-/// None
-///
-pub fn then(option: Option(a), apply fun: fn(a) -> Option(b)) -> Option(b) {
- case option {
- Some(x) -> fun(x)
- None -> None
+ /// Updates a value held within the Some of an Option by calling a given function
+ /// on it, where the given function also returns an Option. The two Options are
+ /// then merged together into one Option.
+ ///
+ /// If the Option is a None rather than Some the function is not called and the
+ /// Option stays the same.
+ ///
+ /// This function is the equivalent of calling `map` followed by `flatten`, and
+ /// it is useful for chaining together multiple functions that return Options.
+ ///
+ /// ## Examples
+ ///
+ /// > then(Some(1), fn(x) { Some(x + 1) })
+ /// Some(2)
+ ///
+ /// > then(Some(1), fn(x) { Some(#("a", x)) })
+ /// Some(#("a", 1))
+ ///
+ /// > then(Some(1), fn(x) { None })
+ /// None
+ ///
+ /// > then(None, fn(x) { Some(x + 1) })
+ /// None
+ ///
+ pub fn then(option: Option(a), apply fun: fn(a) -> Option(b)) -> Option(b) {
+ case option {
+ Some(x) -> fun(x)
+ None -> None
+ }
}
-}
-/// Returns the first value if it is Some, otherwise return the second value.
-///
-/// ## Examples
-///
-/// > or(Some(1), Some(2))
-/// Some(1)
-///
-/// > or(Some(1), None)
-/// Some(1)
-///
-/// > or(None, Some(2))
-/// Some(2)
-///
-/// > or(None, None)
-/// None
-///
-pub fn or(first: Option(a), second: Option(a)) -> Option(a) {
- case first {
- Some(_) -> first
- None -> second
+ /// Returns the first value if it is Some, otherwise return the second value.
+ ///
+ /// ## Examples
+ ///
+ /// > or(Some(1), Some(2))
+ /// Some(1)
+ ///
+ /// > or(Some(1), None)
+ /// Some(1)
+ ///
+ /// > or(None, Some(2))
+ /// Some(2)
+ ///
+ /// > or(None, None)
+ /// None
+ ///
+ pub fn or(first: Option(a), second: Option(a)) -> Option(a) {
+ case first {
+ Some(_) -> first
+ None -> second
+ }
}
-}
-/// Given a list of options
-/// Return only the values inside Some
-///
-/// ## Examples
-///
-/// ```
-/// > values([Some(1), None, Some(3)])
-/// [1, 3]
-/// ```
-///
-pub fn values(options: List(Option(a))) -> List(a) {
- list.filter_map(options, fn(op) { to_result(op, "") })
+ /// Given a list of options
+ /// Return only the values inside Some
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > values([Some(1), None, Some(3)])
+ /// [1, 3]
+ /// ```
+ ///
+ pub fn values(options: List(Option(a))) -> List(a) {
+ list.filter_map(options, fn(op) { to_result(op, "") })
+ }
}
diff --git a/src/gleam/order.gleam b/src/gleam/order.gleam
index c030db4..ee81a62 100644
--- a/src/gleam/order.gleam
+++ b/src/gleam/order.gleam
@@ -1,101 +1,103 @@
-/// Represents the result of a single comparison to determine the precise
-/// ordering of two values.
-///
-pub type Order {
- /// Less-than
- Lt
+if erlang {
+ /// Represents the result of a single comparison to determine the precise
+ /// ordering of two values.
+ ///
+ pub type Order {
+ /// Less-than
+ Lt
- /// Equal
- Eq
+ /// Equal
+ Eq
- /// Greater than
- Gt
-}
+ /// Greater than
+ Gt
+ }
-/// Inverts an order, so less-than becomes greater-than and greater-than
-/// becomes less-than.
-///
-/// ## Examples
-///
-/// > reverse(Lt)
-/// Gt
-///
-/// > reverse(Eq)
-/// Eq
-///
-/// > reverse(Lt)
-/// Gt
-///
-pub fn reverse(order: Order) -> Order {
- case order {
- Lt -> Gt
- Eq -> Eq
- Gt -> Lt
+ /// Inverts an order, so less-than becomes greater-than and greater-than
+ /// becomes less-than.
+ ///
+ /// ## Examples
+ ///
+ /// > reverse(Lt)
+ /// Gt
+ ///
+ /// > reverse(Eq)
+ /// Eq
+ ///
+ /// > reverse(Lt)
+ /// Gt
+ ///
+ pub fn reverse(order: Order) -> Order {
+ case order {
+ Lt -> Gt
+ Eq -> Eq
+ Gt -> Lt
+ }
}
-}
-/// Produces a numeric representation of the order.
-///
-/// ## Examples
-///
-/// > to_int(Lt)
-/// -1
-///
-/// > to_int(Eq)
-/// 0
-///
-/// > to_int(Gt)
-/// 1
-///
-pub fn to_int(order: Order) -> Int {
- case order {
- Lt -> -1
- Eq -> 0
- Gt -> 1
+ /// Produces a numeric representation of the order.
+ ///
+ /// ## Examples
+ ///
+ /// > to_int(Lt)
+ /// -1
+ ///
+ /// > to_int(Eq)
+ /// 0
+ ///
+ /// > to_int(Gt)
+ /// 1
+ ///
+ pub fn to_int(order: Order) -> Int {
+ case order {
+ Lt -> -1
+ Eq -> 0
+ Gt -> 1
+ }
}
-}
-/// Compares two Order values to one another, producing a new Order.
-///
-/// ## Examples
-///
-/// > compare(Eq, with: Lt)
-/// Gt
-///
-pub fn compare(a: Order, with b: Order) -> Order {
- case a, b {
- x, y if x == y -> Eq
- Lt, _ | Eq, Gt -> Lt
- _, _ -> Gt
+ /// Compares two Order values to one another, producing a new Order.
+ ///
+ /// ## Examples
+ ///
+ /// > compare(Eq, with: Lt)
+ /// Gt
+ ///
+ pub fn compare(a: Order, with b: Order) -> Order {
+ case a, b {
+ x, y if x == y -> Eq
+ Lt, _ | Eq, Gt -> Lt
+ _, _ -> Gt
+ }
}
-}
-/// Returns the largest of two orders.
-///
-/// ## Examples
-///
-/// > max(Eq, Lt)
-/// Eq
-///
-pub fn max(a: Order, b: Order) -> Order {
- case a, b {
- Gt, _ -> Gt
- Eq, Lt -> Eq
- _, _ -> b
+ /// Returns the largest of two orders.
+ ///
+ /// ## Examples
+ ///
+ /// > max(Eq, Lt)
+ /// Eq
+ ///
+ pub fn max(a: Order, b: Order) -> Order {
+ case a, b {
+ Gt, _ -> Gt
+ Eq, Lt -> Eq
+ _, _ -> b
+ }
}
-}
-/// Returns the smallest of two orders.
-///
-/// ## Examples
-///
-/// > min(Eq, Lt)
-/// Lt
-///
-pub fn min(a: Order, b: Order) -> Order {
- case a, b {
- Lt, _ -> Lt
- Eq, Gt -> Eq
- _, _ -> b
+ /// Returns the smallest of two orders.
+ ///
+ /// ## Examples
+ ///
+ /// > min(Eq, Lt)
+ /// Lt
+ ///
+ pub fn min(a: Order, b: Order) -> Order {
+ case a, b {
+ Lt, _ -> Lt
+ Eq, Gt -> Eq
+ _, _ -> b
+ }
}
}
diff --git a/src/gleam/os.gleam b/src/gleam/os.gleam
index fcaf724..af67e35 100644
--- a/src/gleam/os.gleam
+++ b/src/gleam/os.gleam
@@ -1,66 +1,69 @@
//// Function to interact with the host operating system.
-import gleam/list
-import gleam/map.{Map}
-import gleam/string
+if erlang {
+ import gleam/list
+ import gleam/map.{Map}
+ import gleam/string
-// Internal type for erlang interop.
-external type CharList
+ // Internal type for erlang interop.
+ external type CharList
-external fn os_getenv() -> List(CharList) =
- "os" "getenv"
+ external fn os_getenv() -> List(CharList) =
+ "os" "getenv"
-external fn os_putenv(key: CharList, value: CharList) -> Bool =
- "os" "putenv"
+ external fn os_putenv(key: CharList, value: CharList) -> Bool =
+ "os" "putenv"
-external fn os_unsetenv(key: CharList) -> Bool =
- "os" "unsetenv"
+ external fn os_unsetenv(key: CharList) -> Bool =
+ "os" "unsetenv"
-external fn char_list_to_string(CharList) -> String =
- "unicode" "characters_to_binary"
+ external fn char_list_to_string(CharList) -> String =
+ "unicode" "characters_to_binary"
-external fn string_to_char_list(String) -> CharList =
- "unicode" "characters_to_list"
+ external fn string_to_char_list(String) -> CharList =
+ "unicode" "characters_to_list"
-/// Returns all environment variables set on the system.
-pub fn get_env() -> Map(String, String) {
- list.map(
- os_getenv(),
- fn(char_list) {
- assert Ok(value) = string.split_once(char_list_to_string(char_list), "=")
- value
- },
- )
- |> map.from_list()
-}
+ /// Returns all environment variables set on the system.
+ pub fn get_env() -> Map(String, String) {
+ list.map(
+ os_getenv(),
+ fn(char_list) {
+ assert Ok(value) =
+ string.split_once(char_list_to_string(char_list), "=")
+ value
+ },
+ )
+ |> map.from_list()
+ }
-/// Sets an environment variable.
-pub fn insert_env(key: String, value: String) -> Nil {
- os_putenv(string_to_char_list(key), string_to_char_list(value))
- Nil
-}
+ /// Sets an environment variable.
+ pub fn insert_env(key: String, value: String) -> Nil {
+ os_putenv(string_to_char_list(key), string_to_char_list(value))
+ Nil
+ }
-/// Deletes an environment variable.
-pub fn delete_env(key: String) -> Nil {
- os_unsetenv(string_to_char_list(key))
- Nil
-}
+ /// Deletes an environment variable.
+ pub fn delete_env(key: String) -> Nil {
+ os_unsetenv(string_to_char_list(key))
+ Nil
+ }
-pub type TimeUnit {
- Second
- Millisecond
- Microsecond
- Nanosecond
-}
+ pub type TimeUnit {
+ Second
+ Millisecond
+ Microsecond
+ Nanosecond
+ }
-/// Returns the current OS system time.
-///
-/// https://erlang.org/doc/apps/erts/time_correction.html#OS_System_Time
-pub external fn system_time(TimeUnit) -> Int =
- "os" "system_time"
+ /// Returns the current OS system time.
+ ///
+ /// https://erlang.org/doc/apps/erts/time_correction.html#OS_System_Time
+ pub external fn system_time(TimeUnit) -> Int =
+ "os" "system_time"
-/// Returns the current OS system time as a tuple of Ints
-///
-/// http://erlang.org/doc/man/os.html#timestamp-0
-pub external fn erlang_timestamp() -> #(Int, Int, Int) =
- "os" "timestamp"
+ /// Returns the current OS system time as a tuple of Ints
+ ///
+ /// http://erlang.org/doc/man/os.html#timestamp-0
+ pub external fn erlang_timestamp() -> #(Int, Int, Int) =
+ "os" "timestamp"
+}
diff --git a/src/gleam/pair.gleam b/src/gleam/pair.gleam
index 6143ee9..246ce8c 100644
--- a/src/gleam/pair.gleam
+++ b/src/gleam/pair.gleam
@@ -1,61 +1,63 @@
-/// Returns the first element in a pair.
-///
-/// ## Examples
-///
-/// > first(#(1, 2))
-/// 1
-///
-pub fn first(pair: #(a, b)) -> a {
- let #(a, _) = pair
- a
-}
+if erlang {
+ /// Returns the first element in a pair.
+ ///
+ /// ## Examples
+ ///
+ /// > first(#(1, 2))
+ /// 1
+ ///
+ pub fn first(pair: #(a, b)) -> a {
+ let #(a, _) = pair
+ a
+ }
-/// Returns the second element in a pair.
-///
-/// ## Examples
-///
-/// > second(#(1, 2))
-/// 2
-///
-pub fn second(pair: #(a, b)) -> b {
- let #(_, a) = pair
- a
-}
+ /// Returns the second element in a pair.
+ ///
+ /// ## Examples
+ ///
+ /// > second(#(1, 2))
+ /// 2
+ ///
+ pub fn second(pair: #(a, b)) -> b {
+ let #(_, a) = pair
+ a
+ }
-/// Returns a new pair with the elements swapped.
-///
-/// ## Examples
-///
-/// > swap(#(1, 2))
-/// #(2, 1)
-///
-pub fn swap(pair: #(a, b)) -> #(b, a) {
- let #(a, b) = pair
- #(b, a)
-}
+ /// Returns a new pair with the elements swapped.
+ ///
+ /// ## Examples
+ ///
+ /// > swap(#(1, 2))
+ /// #(2, 1)
+ ///
+ pub fn swap(pair: #(a, b)) -> #(b, a) {
+ let #(a, b) = pair
+ #(b, a)
+ }
-/// Returns a new pair with the first element having had `with` applied to
-/// it.
-///
-/// ## Examples
-///
-/// > #(1, 2) |> map_first(fn(n) { n * 2 })
-/// 2
-///
-pub fn map_first(of pair: #(a, b), with fun: fn(a) -> c) -> #(c, b) {
- let #(a, b) = pair
- #(fun(a), b)
-}
+ /// Returns a new pair with the first element having had `with` applied to
+ /// it.
+ ///
+ /// ## Examples
+ ///
+ /// > #(1, 2) |> map_first(fn(n) { n * 2 })
+ /// 2
+ ///
+ pub fn map_first(of pair: #(a, b), with fun: fn(a) -> c) -> #(c, b) {
+ let #(a, b) = pair
+ #(fun(a), b)
+ }
-/// Returns a new pair with the second element having had `with` applied to
-/// it.
-///
-/// ## Examples
-///
-/// > #(1, 2) |> map_second(fn(n) { n * 2 })
-/// 4
-///
-pub fn map_second(of pair: #(a, b), with fun: fn(b) -> c) -> #(a, c) {
- let #(a, b) = pair
- #(a, fun(b))
+ /// Returns a new pair with the second element having had `with` applied to
+ /// it.
+ ///
+ /// ## Examples
+ ///
+ /// > #(1, 2) |> map_second(fn(n) { n * 2 })
+ /// 4
+ ///
+ pub fn map_second(of pair: #(a, b), with fun: fn(b) -> c) -> #(a, c) {
+ let #(a, b) = pair
+ #(a, fun(b))
+ }
}
diff --git a/src/gleam/queue.gleam b/src/gleam/queue.gleam
index 6b12cfb..80cea16 100644
--- a/src/gleam/queue.gleam
+++ b/src/gleam/queue.gleam
@@ -1,254 +1,258 @@
-import gleam/list
+if erlang {
+ import gleam/list
-/// A queue is an order collection of elements. It is similar to a list, but
-/// unlike a list elements can be added to or removed from either the front or
-/// the back in a performant fashion.
-///
-/// The internal representation may be different for two queues with the same
-/// elements in the same order if the queues were constructed in different
-/// ways. This is the price paid for a queue's fast access at both the front
-/// and the back.
-///
-/// Because of unpredictable internal representation the equality operator `==`
-/// may return surprising results, and the `is_equal` and `is_logically_equal`
-/// functions are the recommended way to test queues for equality.
-///
-pub opaque type Queue(element) {
- Queue(in: List(element), out: List(element))
-}
+ /// A queue is an order collection of elements. It is similar to a list, but
+ /// unlike a list elements can be added to or removed from either the front or
+ /// the back in a performant fashion.
+ ///
+ /// The internal representation may be different for two queues with the same
+ /// elements in the same order if the queues were constructed in different
+ /// ways. This is the price paid for a queue's fast access at both the front
+ /// and the back.
+ ///
+ /// Because of unpredictable internal representation the equality operator `==`
+ /// may return surprising results, and the `is_equal` and `is_logically_equal`
+ /// functions are the recommended way to test queues for equality.
+ ///
+ pub opaque type Queue(element) {
+ Queue(in: List(element), out: List(element))
+ }
-/// Creates a fresh queue that contains no values.
-///
-pub fn new() -> Queue(a) {
- Queue(in: [], out: [])
-}
+ /// Creates a fresh queue that contains no values.
+ ///
+ pub fn new() -> Queue(a) {
+ Queue(in: [], out: [])
+ }
-/// Converts a list of elements into a queue of the same elements in the same
-/// order. The head element in the list becomes the front element in the queue.
-///
-/// This function runs in constant time.
-///
-/// # Examples
-///
-/// > [1, 2, 3] |> from_list |> length
-/// 3
-///
-pub fn from_list(list: List(a)) -> Queue(a) {
- Queue(in: [], out: list)
-}
+ /// Converts a list of elements into a queue of the same elements in the same
+ /// order. The head element in the list becomes the front element in the queue.
+ ///
+ /// This function runs in constant time.
+ ///
+ /// # Examples
+ ///
+ /// > [1, 2, 3] |> from_list |> length
+ /// 3
+ ///
+ pub fn from_list(list: List(a)) -> Queue(a) {
+ Queue(in: [], out: list)
+ }
-/// Converts a queue of elements into a list of the same elements in the same
-/// order. The front element in the queue becomes the head element in the list.
-///
-/// This function runs in linear time.
-///
-/// # Examples
-///
-/// > new() |> push_back(1) |> push_back(2) |> to_list
-/// [1, 2]
-///
-pub fn to_list(queue: Queue(a)) -> List(a) {
- queue.out
- |> list.append(list.reverse(queue.in))
-}
+ /// Converts a queue of elements into a list of the same elements in the same
+ /// order. The front element in the queue becomes the head element in the list.
+ ///
+ /// This function runs in linear time.
+ ///
+ /// # Examples
+ ///
+ /// > new() |> push_back(1) |> push_back(2) |> to_list
+ /// [1, 2]
+ ///
+ pub fn to_list(queue: Queue(a)) -> List(a) {
+ queue.out
+ |> list.append(list.reverse(queue.in))
+ }
-/// Determines whether or not the queue is empty.
-///
-/// This function runs in constant time.
-///
-/// ## Examples
-///
-/// > [] |> from_list |> is_empty
-/// True
-///
-/// > [1] |> from_list |> is_empty
-/// False
-///
-/// > [1, 2] |> from_list |> is_empty
-/// False
-///
-pub fn is_empty(queue: Queue(a)) -> Bool {
- queue.in == [] && queue.out == []
-}
+ /// Determines whether or not the queue is empty.
+ ///
+ /// This function runs in constant time.
+ ///
+ /// ## Examples
+ ///
+ /// > [] |> from_list |> is_empty
+ /// True
+ ///
+ /// > [1] |> from_list |> is_empty
+ /// False
+ ///
+ /// > [1, 2] |> from_list |> is_empty
+ /// False
+ ///
+ pub fn is_empty(queue: Queue(a)) -> Bool {
+ queue.in == [] && queue.out == []
+ }
-/// Counts the number of elements in a given queue.
-///
-/// This function has to traverse the queue to determine the number of elements,
-/// so it runs in linear time.
-///
-/// ## Examples
-///
-/// > length(from_list([]))
-/// 0
-///
-/// > length(from_list([1]))
-/// 1
-///
-/// > length(from_list([1, 2]))
-/// 2
-///
-pub fn length(queue: Queue(a)) -> Int {
- list.length(queue.in) + list.length(queue.out)
-}
+ /// Counts the number of elements in a given queue.
+ ///
+ /// This function has to traverse the queue to determine the number of elements,
+ /// so it runs in linear time.
+ ///
+ /// ## Examples
+ ///
+ /// > length(from_list([]))
+ /// 0
+ ///
+ /// > length(from_list([1]))
+ /// 1
+ ///
+ /// > length(from_list([1, 2]))
+ /// 2
+ ///
+ pub fn length(queue: Queue(a)) -> Int {
+ list.length(queue.in) + list.length(queue.out)
+ }
-/// Pushes an element onto the back of the queue.
-///
-/// # Examples
-///
-/// > [1, 2] |> from_list |> push_back(3) |> to_list
-/// [1, 2, 3]
-///
-pub fn push_back(onto queue: Queue(a), this item: a) -> Queue(a) {
- Queue(in: [item, ..queue.in], out: queue.out)
-}
+ /// Pushes an element onto the back of the queue.
+ ///
+ /// # Examples
+ ///
+ /// > [1, 2] |> from_list |> push_back(3) |> to_list
+ /// [1, 2, 3]
+ ///
+ pub fn push_back(onto queue: Queue(a), this item: a) -> Queue(a) {
+ Queue(in: [item, ..queue.in], out: queue.out)
+ }
-/// Pushes an element onto the front of the queue.
-///
-/// # Examples
-///
-/// > [0, 0] |> from_list |> push_front(1) |> to_list
-/// [1, 0, 0]
-///
-pub fn push_front(onto queue: Queue(a), this item: a) -> Queue(a) {
- Queue(in: queue.in, out: [item, ..queue.out])
-}
+ /// Pushes an element onto the front of the queue.
+ ///
+ /// # Examples
+ ///
+ /// > [0, 0] |> from_list |> push_front(1) |> to_list
+ /// [1, 0, 0]
+ ///
+ pub fn push_front(onto queue: Queue(a), this item: a) -> Queue(a) {
+ Queue(in: queue.in, out: [item, ..queue.out])
+ }
-/// Gets the last element from the queue, returning the
-/// element and a new queue without that element.
-///
-/// This function typically runs in constant time, but will occasionally run in
-/// linear time.
-///
-/// # Examples
-///
-/// > queue.new()
-/// > |> queue.push_back(0)
-/// > |> queue.push_back(1)
-/// > |> queue.pop_back()
-/// Ok(#(1, queue.push_front(queue.new(), 0)))
-///
-/// > queue.new()
-/// > |> queue.push_front(0)
-/// > |> queue.pop_back()
-/// Ok(#(0, queue.new()))
-///
-/// > queue.new()
-/// > |> queue.pop_back()
-/// Error(Nil)
-///
-pub fn pop_back(from queue: Queue(a)) -> Result(#(a, Queue(a)), Nil) {
- case queue {
- Queue(in: [], out: []) -> Error(Nil)
- Queue(in: [], out: out) -> pop_back(Queue(in: list.reverse(out), out: []))
- Queue(in: [first, ..rest], out: out) -> {
- let queue = Queue(in: rest, out: out)
- Ok(#(first, queue))
+ /// Gets the last element from the queue, returning the
+ /// element and a new queue without that element.
+ ///
+ /// This function typically runs in constant time, but will occasionally run in
+ /// linear time.
+ ///
+ /// # Examples
+ ///
+ /// > queue.new()
+ /// > |> queue.push_back(0)
+ /// > |> queue.push_back(1)
+ /// > |> queue.pop_back()
+ /// Ok(#(1, queue.push_front(queue.new(), 0)))
+ ///
+ /// > queue.new()
+ /// > |> queue.push_front(0)
+ /// > |> queue.pop_back()
+ /// Ok(#(0, queue.new()))
+ ///
+ /// > queue.new()
+ /// > |> queue.pop_back()
+ /// Error(Nil)
+ ///
+ pub fn pop_back(from queue: Queue(a)) -> Result(#(a, Queue(a)), Nil) {
+ case queue {
+ Queue(in: [], out: []) -> Error(Nil)
+ Queue(in: [], out: out) -> pop_back(Queue(in: list.reverse(out), out: []))
+ Queue(in: [first, ..rest], out: out) -> {
+ let queue = Queue(in: rest, out: out)
+ Ok(#(first, queue))
+ }
}
}
-}
-/// Gets the first element from the queue, returning the
-/// element and a new queue without that element.
-///
-/// This function typically runs in constant time, but will occasionally run in
-/// linear time.
-///
-/// # Examples
-///
-/// > queue.new()
-/// > |> queue.push_front(1)
-/// > |> queue.push_front(0)
-/// > |> queue.pop_front()
-/// Ok(#(0, queue.push_back(queue.new(), 1)))
-///
-/// > queue.new()
-/// > |> queue.push_back(0)
-/// > |> queue.pop_front()
-/// Ok(#(0, queue.new()))
-///
-/// > queue.new()
-/// > |> queue.pop_back()
-/// Error(Nil)
-///
-pub fn pop_front(from queue: Queue(a)) -> Result(#(a, Queue(a)), Nil) {
- case queue {
- Queue(in: [], out: []) -> Error(Nil)
- Queue(in: in, out: []) -> pop_front(Queue(in: [], out: list.reverse(in)))
- Queue(in: in, out: [first, ..rest]) -> {
- let queue = Queue(in: in, out: rest)
- Ok(#(first, queue))
+ /// Gets the first element from the queue, returning the
+ /// element and a new queue without that element.
+ ///
+ /// This function typically runs in constant time, but will occasionally run in
+ /// linear time.
+ ///
+ /// # Examples
+ ///
+ /// > queue.new()
+ /// > |> queue.push_front(1)
+ /// > |> queue.push_front(0)
+ /// > |> queue.pop_front()
+ /// Ok(#(0, queue.push_back(queue.new(), 1)))
+ ///
+ /// > queue.new()
+ /// > |> queue.push_back(0)
+ /// > |> queue.pop_front()
+ /// Ok(#(0, queue.new()))
+ ///
+ /// > queue.new()
+ /// > |> queue.pop_back()
+ /// Error(Nil)
+ ///
+ pub fn pop_front(from queue: Queue(a)) -> Result(#(a, Queue(a)), Nil) {
+ case queue {
+ Queue(in: [], out: []) -> Error(Nil)
+ Queue(in: in, out: []) -> pop_front(Queue(in: [], out: list.reverse(in)))
+ Queue(in: in, out: [first, ..rest]) -> {
+ let queue = Queue(in: in, out: rest)
+ Ok(#(first, queue))
+ }
}
}
-}
-/// Creates a new queue from a given queue containing the same elements, but in
-/// the opposite order.
-///
-/// This function runs in constant time.
-///
-/// ## Examples
-///
-/// > reverse(from_list([]))
-/// []
-///
-/// > reverse(from_list([1]))
-/// [1]
-///
-/// > reverse(from_list([1, 2]))
-/// [2, 1]
-///
-pub fn reverse(queue: Queue(a)) -> Queue(a) {
- Queue(in: queue.out, out: queue.in)
-}
+ /// Creates a new queue from a given queue containing the same elements, but in
+ /// the opposite order.
+ ///
+ /// This function runs in constant time.
+ ///
+ /// ## Examples
+ ///
+ /// > reverse(from_list([]))
+ /// []
+ ///
+ /// > reverse(from_list([1]))
+ /// [1]
+ ///
+ /// > reverse(from_list([1, 2]))
+ /// [2, 1]
+ ///
+ pub fn reverse(queue: Queue(a)) -> Queue(a) {
+ Queue(in: queue.out, out: queue.in)
+ }
-fn check_equal(
- xs: List(t),
- x_tail: List(t),
- ys: List(t),
- y_tail: List(t),
- eq: fn(t, t) -> Bool,
-) -> Bool {
- case xs, x_tail, ys, y_tail {
- [], [], [], [] -> True
- [x, ..xs], _, [y, ..ys], _ ->
- case eq(x, y) {
- False -> False
- True -> check_equal(xs, x_tail, ys, y_tail, eq)
- }
- [], [_, .._], _, _ -> check_equal(list.reverse(x_tail), [], ys, y_tail, eq)
- _, _, [], [_, .._] -> check_equal(xs, x_tail, list.reverse(y_tail), [], eq)
- _, _, _, _ -> False
+ fn check_equal(
+ xs: List(t),
+ x_tail: List(t),
+ ys: List(t),
+ y_tail: List(t),
+ eq: fn(t, t) -> Bool,
+ ) -> Bool {
+ case xs, x_tail, ys, y_tail {
+ [], [], [], [] -> True
+ [x, ..xs], _, [y, ..ys], _ ->
+ case eq(x, y) {
+ False -> False
+ True -> check_equal(xs, x_tail, ys, y_tail, eq)
+ }
+ [], [_, .._], _, _ ->
+ check_equal(list.reverse(x_tail), [], ys, y_tail, eq)
+ _, _, [], [_, .._] ->
+ check_equal(xs, x_tail, list.reverse(y_tail), [], eq)
+ _, _, _, _ -> False
+ }
}
-}
-/// Checks whether two queues have equal elements in the same order, where the
-/// equality of elements is determined by a given equality checking function.
-///
-/// This function is useful as the internal representation may be different for
-/// two queues with the same elements in the same order depending on how they
-/// were constructed, so the equality operator `==` may return surprising
-/// results.
-///
-/// This function runs in linear time multiplied by the time taken by the
-/// element equality checking function.
-///
-pub fn is_logically_equal(
- a: Queue(t),
- to b: Queue(t),
- checking element_is_equal: fn(t, t) -> Bool,
-) -> Bool {
- check_equal(a.out, a.in, b.out, b.in, element_is_equal)
-}
+ /// Checks whether two queues have equal elements in the same order, where the
+ /// equality of elements is determined by a given equality checking function.
+ ///
+ /// This function is useful as the internal representation may be different for
+ /// two queues with the same elements in the same order depending on how they
+ /// were constructed, so the equality operator `==` may return surprising
+ /// results.
+ ///
+ /// This function runs in linear time multiplied by the time taken by the
+ /// element equality checking function.
+ ///
+ pub fn is_logically_equal(
+ a: Queue(t),
+ to b: Queue(t),
+ checking element_is_equal: fn(t, t) -> Bool,
+ ) -> Bool {
+ check_equal(a.out, a.in, b.out, b.in, element_is_equal)
+ }
-/// Checks whether two queues have the same elements in the same order.
-///
-/// This function is useful as the internal representation may be different for
-/// two queues with the same elements in the same order depending on how they
-/// were constructed, so the equality operator `==` may return surprising
-/// results.
-///
-/// This function runs in linear time.
-///
-pub fn is_equal(a: Queue(t), to b: Queue(t)) -> Bool {
- check_equal(a.out, a.in, b.out, b.in, fn(a, b) { a == b })
+ /// Checks whether two queues have the same elements in the same order.
+ ///
+ /// This function is useful as the internal representation may be different for
+ /// two queues with the same elements in the same order depending on how they
+ /// were constructed, so the equality operator `==` may return surprising
+ /// results.
+ ///
+ /// This function runs in linear time.
+ ///
+ pub fn is_equal(a: Queue(t), to b: Queue(t)) -> Bool {
+ check_equal(a.out, a.in, b.out, b.in, fn(a, b) { a == b })
+ }
}
diff --git a/src/gleam/regex.gleam b/src/gleam/regex.gleam
index 07aa1ba..87f06c8 100644
--- a/src/gleam/regex.gleam
+++ b/src/gleam/regex.gleam
@@ -3,121 +3,123 @@
//// all of the PCRE library is interfaced and some parts of the library go beyond
//// what PCRE offers. Currently PCRE version 8.40 (release date 2017-01-11) is used.
-import gleam/option.{Option}
+if erlang {
+ import gleam/option.{Option}
-pub external type Regex
+ pub external type Regex
-/// The details about a particular match:
-///
-pub type Match {
- Match(
- /// The full string of the match.
- content: String,
- /// The byte index of the match in the original string.
- byte_index: Int,
- /// A Regex can have subpatterns, sup-parts that are in parentheses.
- submatches: List(Option(String)),
- )
-}
+ /// The details about a particular match:
+ ///
+ pub type Match {
+ Match(
+ /// The full string of the match.
+ content: String,
+ /// The byte index of the match in the original string.
+ byte_index: Int,
+ /// A Regex can have subpatterns, sup-parts that are in parentheses.
+ submatches: List(Option(String)),
+ )
+ }
-/// When a regular expression fails to compile:
-///
-pub type CompileError {
- CompileError(
- /// The problem encountered that caused the compilation to fail
- error: String,
- /// The byte index into the string to where the problem was found
- byte_index: Int,
- )
-}
+ /// When a regular expression fails to compile:
+ ///
+ pub type CompileError {
+ CompileError(
+ /// The problem encountered that caused the compilation to fail
+ error: String,
+ /// The byte index into the string to where the problem was found
+ byte_index: Int,
+ )
+ }
-pub type Options {
- Options(case_insensitive: Bool, multi_line: Bool)
-}
+ pub type Options {
+ Options(case_insensitive: Bool, multi_line: Bool)
+ }
-/// Creates a Regex with some additional options.
-///
-/// ## Examples
-///
-/// > let options = Options(case_insensitive: False, multi_line: True)
-/// > assert Ok(re) = compile("^[0-9]", with: options)
-/// > match(re, "abc\n123")
-/// True
-///
-/// > let options = Options(case_insensitive: True, multi_line: False)
-/// > assert Ok(re) = compile("[A-Z]", with: options)
-/// > match(re, "abc123")
-/// True
-///
-pub external fn compile(String, with: Options) -> Result(Regex, CompileError) =
- "gleam_stdlib" "compile_regex"
+ /// Creates a Regex with some additional options.
+ ///
+ /// ## Examples
+ ///
+ /// > let options = Options(case_insensitive: False, multi_line: True)
+ /// > assert Ok(re) = compile("^[0-9]", with: options)
+ /// > match(re, "abc\n123")
+ /// True
+ ///
+ /// > let options = Options(case_insensitive: True, multi_line: False)
+ /// > assert Ok(re) = compile("[A-Z]", with: options)
+ /// > match(re, "abc123")
+ /// True
+ ///
+ pub external fn compile(String, with: Options) -> Result(Regex, CompileError) =
+ "gleam_stdlib" "compile_regex"
-/// Creates a new Regex.
-///
-/// ## Examples
-///
-/// > assert Ok(re) = from_string("[0-9]")
-/// > match(re, "abc123")
-/// True
-///
-/// > match(re, "abcxyz")
-/// False
-///
-/// > from_string("[0-9")
-/// Error(
-/// CompileError(
-/// error: "missing terminating ] for character class",
-/// byte_index: 4
-/// )
-/// )
-///
-pub fn from_string(pattern: String) -> Result(Regex, CompileError) {
- compile(pattern, Options(case_insensitive: False, multi_line: False))
-}
+ /// Creates a new Regex.
+ ///
+ /// ## Examples
+ ///
+ /// > assert Ok(re) = from_string("[0-9]")
+ /// > match(re, "abc123")
+ /// True
+ ///
+ /// > match(re, "abcxyz")
+ /// False
+ ///
+ /// > from_string("[0-9")
+ /// Error(
+ /// CompileError(
+ /// error: "missing terminating ] for character class",
+ /// byte_index: 4
+ /// )
+ /// )
+ ///
+ pub fn from_string(pattern: String) -> Result(Regex, CompileError) {
+ compile(pattern, Options(case_insensitive: False, multi_line: False))
+ }
-/// Returns a boolean indicating whether there was a match or not.
-///
-/// ## Examples
-///
-/// > assert Ok(re) = from_string("^f.o.?")
-/// > check(with: re, content: "foo")
-/// True
-///
-/// > check(with: re, content: "boo")
-/// False
-///
-pub external fn check(with: Regex, content: String) -> Bool =
- "gleam_stdlib" "regex_match"
+ /// Returns a boolean indicating whether there was a match or not.
+ ///
+ /// ## Examples
+ ///
+ /// > assert Ok(re) = from_string("^f.o.?")
+ /// > check(with: re, content: "foo")
+ /// True
+ ///
+ /// > check(with: re, content: "boo")
+ /// False
+ ///
+ pub external fn check(with: Regex, content: String) -> Bool =
+ "gleam_stdlib" "regex_match"
-/// Splits a string
-///
-/// ## Examples
-///
-/// > assert Ok(re) = from_string(" *, *")
-/// > split(with: re, content: "foo,32, 4, 9 ,0")
-/// ["foo", "32", "4", "9", "0"]
-///
-pub external fn split(with: Regex, content: String) -> List(String) =
- "gleam_stdlib" "regex_split"
+ /// Splits a string
+ ///
+ /// ## Examples
+ ///
+ /// > assert Ok(re) = from_string(" *, *")
+ /// > split(with: re, content: "foo,32, 4, 9 ,0")
+ /// ["foo", "32", "4", "9", "0"]
+ ///
+ pub external fn split(with: Regex, content: String) -> List(String) =
+ "gleam_stdlib" "regex_split"
-/// Collects all matches of the regular expression.
-///
-/// ## Examples
-///
-/// > assert Ok(re) = regex.from_string("[oi]n a (\\w+)")
-/// > regex.scan(with: re, content: "I am on a boat in a lake.")
-/// [
-/// Match(
-/// content: "on a boat",
-/// byte_index: 5,
-/// submatches: [Some("boat")]
-/// ),
-/// Match(
-/// content: "in a lake",
-/// byte_index: 15,
-/// submatches: [Some("lake")]
-/// )
-/// ]
-///
-pub external fn scan(with: Regex, content: String) -> List(Match) =
- "gleam_stdlib" "regex_scan"
+ /// Collects all matches of the regular expression.
+ ///
+ /// ## Examples
+ ///
+ /// > assert Ok(re) = regex.from_string("[oi]n a (\\w+)")
+ /// > regex.scan(with: re, content: "I am on a boat in a lake.")
+ /// [
+ /// Match(
+ /// content: "on a boat",
+ /// byte_index: 5,
+ /// submatches: [Some("boat")]
+ /// ),
+ /// Match(
+ /// content: "in a lake",
+ /// byte_index: 15,
+ /// submatches: [Some("lake")]
+ /// )
+ /// ]
+ ///
+ pub external fn scan(with: Regex, content: String) -> List(Match) =
+ "gleam_stdlib" "regex_scan"
+}
diff --git a/src/gleam/result.gleam b/src/gleam/result.gleam
index d0601bf..4527516 100644
--- a/src/gleam/result.gleam
+++ b/src/gleam/result.gleam
@@ -1,280 +1,282 @@
-import gleam/list
+if erlang {
+ import gleam/list
-/// Result represents the result of something that may succeed or not.
-/// `Ok` means it was successful, `Error` means it was not successful.
-///
-pub type Result(success, error) =
- Result(success, error)
+ /// Result represents the result of something that may succeed or not.
+ /// `Ok` means it was successful, `Error` means it was not successful.
+ ///
+ pub type Result(success, error) =
+ Result(success, error)
-/// Nil is a type used to represent the absence of something, similar to null
-/// or undefined in other languages.
-///
-/// Unlike some other languages values cannot be implicitly nil.
-///
-pub type Nil =
- Nil
+ /// Nil is a type used to represent the absence of something, similar to null
+ /// or undefined in other languages.
+ ///
+ /// Unlike some other languages values cannot be implicitly nil.
+ ///
+ pub type Nil =
+ Nil
-/// Checks whether the result is an Ok value.
-///
-/// ## Examples
-///
-/// > is_ok(Ok(1))
-/// True
-///
-/// > is_ok(Error(Nil))
-/// False
-///
-pub fn is_ok(result: Result(a, e)) -> Bool {
- case result {
- Error(_) -> False
- Ok(_) -> True
+ /// Checks whether the result is an Ok value.
+ ///
+ /// ## Examples
+ ///
+ /// > is_ok(Ok(1))
+ /// True
+ ///
+ /// > is_ok(Error(Nil))
+ /// False
+ ///
+ pub fn is_ok(result: Result(a, e)) -> Bool {
+ case result {
+ Error(_) -> False
+ Ok(_) -> True
+ }
}
-}
-/// Checks whether the result is an Error value.
-///
-/// ## Examples
-///
-/// > is_error(Ok(1))
-/// False
-///
-/// > is_error(Error(Nil))
-/// True
-///
-pub fn is_error(result: Result(a, e)) -> Bool {
- case result {
- Ok(_) -> False
- Error(_) -> True
+ /// Checks whether the result is an Error value.
+ ///
+ /// ## Examples
+ ///
+ /// > is_error(Ok(1))
+ /// False
+ ///
+ /// > is_error(Error(Nil))
+ /// True
+ ///
+ pub fn is_error(result: Result(a, e)) -> Bool {
+ case result {
+ Ok(_) -> False
+ Error(_) -> True
+ }
}
-}
-/// Updates a value held within the Ok of a result by calling a given function
-/// on it.
-///
-/// If the result is an Error rather than OK the function is not called and the
-/// result stays the same.
-///
-/// ## Examples
-///
-/// > map(over: Ok(1), with: fn(x) { x + 1 })
-/// Ok(2)
-///
-/// > map(over: Error(1), with: fn(x) { x + 1 })
-/// Error(1)
-///
-pub fn map(over result: Result(a, e), with fun: fn(a) -> b) -> Result(b, e) {
- case result {
- Ok(x) -> Ok(fun(x))
- Error(e) -> Error(e)
+ /// Updates a value held within the Ok of a result by calling a given function
+ /// on it.
+ ///
+ /// If the result is an Error rather than OK the function is not called and the
+ /// result stays the same.
+ ///
+ /// ## Examples
+ ///
+ /// > map(over: Ok(1), with: fn(x) { x + 1 })
+ /// Ok(2)
+ ///
+ /// > map(over: Error(1), with: fn(x) { x + 1 })
+ /// Error(1)
+ ///
+ pub fn map(over result: Result(a, e), with fun: fn(a) -> b) -> Result(b, e) {
+ case result {
+ Ok(x) -> Ok(fun(x))
+ Error(e) -> Error(e)
+ }
}
-}
-/// Updates a value held within the Error of a result by calling a given function
-/// on it.
-///
-/// If the result is Ok rather than Error the function is not called and the
-/// result stays the same.
-///
-/// ## Examples
-///
-/// > map_error(over: Error(1), with: fn(x) { x + 1 })
-/// Error(2)
-///
-/// > map_error(over: Ok(1), with: fn(x) { x + 1 })
-/// Ok(1)
-///
-pub fn map_error(
- over result: Result(a, e),
- with fun: fn(e) -> f,
-) -> Result(a, f) {
- case result {
- Ok(x) -> Ok(x)
- Error(error) -> Error(fun(error))
+ /// Updates a value held within the Error of a result by calling a given function
+ /// on it.
+ ///
+ /// If the result is Ok rather than Error the function is not called and the
+ /// result stays the same.
+ ///
+ /// ## Examples
+ ///
+ /// > map_error(over: Error(1), with: fn(x) { x + 1 })
+ /// Error(2)
+ ///
+ /// > map_error(over: Ok(1), with: fn(x) { x + 1 })
+ /// Ok(1)
+ ///
+ pub fn map_error(
+ over result: Result(a, e),
+ with fun: fn(e) -> f,
+ ) -> Result(a, f) {
+ case result {
+ Ok(x) -> Ok(x)
+ Error(error) -> Error(fun(error))
+ }
}
-}
-/// Merges a nested Result into a single layer.
-///
-/// ## Examples
-///
-/// > flatten(Ok(Ok(1)))
-/// Ok(1)
-///
-/// > flatten(Ok(Error(""))
-/// Error("")
-///
-/// > flatten(Error(Nil))
-/// Error(Nil)
-///
-pub fn flatten(result: Result(Result(a, e), e)) -> Result(a, e) {
- case result {
- Ok(x) -> x
- Error(error) -> Error(error)
+ /// Merges a nested Result into a single layer.
+ ///
+ /// ## Examples
+ ///
+ /// > flatten(Ok(Ok(1)))
+ /// Ok(1)
+ ///
+ /// > flatten(Ok(Error(""))
+ /// Error("")
+ ///
+ /// > flatten(Error(Nil))
+ /// Error(Nil)
+ ///
+ pub fn flatten(result: Result(Result(a, e), e)) -> Result(a, e) {
+ case result {
+ Ok(x) -> x
+ Error(error) -> Error(error)
+ }
}
-}
-/// Updates a value held within the Ok of a result by calling a given function
-/// on it, where the given function also returns a result. The two results are
-/// then merged together into one result.
-///
-/// If the result is an Error rather than OK the function is not called and the
-/// result stays the same.
-///
-/// This function is the equivalent of calling `map` followed by `flatten`, and
-/// it is useful for chaining together multiple functions that may fail.
-///
-/// ## Examples
-///
-/// > then(Ok(1), fn(x) { Ok(x + 1) })
-/// Ok(2)
-///
-/// > then(Ok(1), fn(x) { Ok(#("a", x)) })
-/// Ok(#("a", 1))
-///
-/// > then(Ok(1), fn(x) { Error("Oh no") })
-/// Error("Oh no")
-///
-/// > then(Error(Nil), fn(x) { Ok(x + 1) })
-/// Error(Nil)
-///
-pub fn then(
- result: Result(a, e),
- apply fun: fn(a) -> Result(b, e),
-) -> Result(b, e) {
- case result {
- Ok(x) -> fun(x)
- Error(e) -> Error(e)
+ /// Updates a value held within the Ok of a result by calling a given function
+ /// on it, where the given function also returns a result. The two results are
+ /// then merged together into one result.
+ ///
+ /// If the result is an Error rather than OK the function is not called and the
+ /// result stays the same.
+ ///
+ /// This function is the equivalent of calling `map` followed by `flatten`, and
+ /// it is useful for chaining together multiple functions that may fail.
+ ///
+ /// ## Examples
+ ///
+ /// > then(Ok(1), fn(x) { Ok(x + 1) })
+ /// Ok(2)
+ ///
+ /// > then(Ok(1), fn(x) { Ok(#("a", x)) })
+ /// Ok(#("a", 1))
+ ///
+ /// > then(Ok(1), fn(x) { Error("Oh no") })
+ /// Error("Oh no")
+ ///
+ /// > then(Error(Nil), fn(x) { Ok(x + 1) })
+ /// Error(Nil)
+ ///
+ pub fn then(
+ result: Result(a, e),
+ apply fun: fn(a) -> Result(b, e),
+ ) -> Result(b, e) {
+ case result {
+ Ok(x) -> fun(x)
+ Error(e) -> Error(e)
+ }
}
-}
-/// Extracts the Ok value from a result, returning a default value if the result
-/// is an Error.
-///
-/// ## Examples
-///
-/// > unwrap(Ok(1), 0)
-/// 1
-///
-/// > unwrap(Error(""), 0)
-/// 0
-///
-pub fn unwrap(result: Result(a, e), or default: a) -> a {
- case result {
- Ok(v) -> v
- Error(_) -> default
+ /// Extracts the Ok value from a result, returning a default value if the result
+ /// is an Error.
+ ///
+ /// ## Examples
+ ///
+ /// > unwrap(Ok(1), 0)
+ /// 1
+ ///
+ /// > unwrap(Error(""), 0)
+ /// 0
+ ///
+ pub fn unwrap(result: Result(a, e), or default: a) -> a {
+ case result {
+ Ok(v) -> v
+ Error(_) -> default
+ }
}
-}
-/// Extracts the Ok value from a result, evaluating the default function if the result
-/// is an Error.
-///
-/// ## Examples
-///
-/// > lazy_unwrap(Ok(1), fn() { 0 })
-/// 1
-///
-/// > lazy_unwrap(Error(""), fn() { 0 })
-/// 0
-///
-pub fn lazy_unwrap(result: Result(a, e), or default: fn() -> a) -> a {
- case result {
- Ok(v) -> v
- Error(_) -> default()
+ /// Extracts the Ok value from a result, evaluating the default function if the result
+ /// is an Error.
+ ///
+ /// ## Examples
+ ///
+ /// > lazy_unwrap(Ok(1), fn() { 0 })
+ /// 1
+ ///
+ /// > lazy_unwrap(Error(""), fn() { 0 })
+ /// 0
+ ///
+ pub fn lazy_unwrap(result: Result(a, e), or default: fn() -> a) -> a {
+ case result {
+ Ok(v) -> v
+ Error(_) -> default()
+ }
}
-}
-/// Transforms any error into Error(Nil)
-///
-/// ## Examples
-///
-/// > nil_error(Error(1))
-/// Error(Nil)
-///
-/// > nil_error(Ok(1))
-/// Ok(1)
-///
-pub fn nil_error(result: Result(a, e)) -> Result(a, Nil) {
- map_error(result, fn(_) { Nil })
-}
+ /// Transforms any error into Error(Nil)
+ ///
+ /// ## Examples
+ ///
+ /// > nil_error(Error(1))
+ /// Error(Nil)
+ ///
+ /// > nil_error(Ok(1))
+ /// Ok(1)
+ ///
+ pub fn nil_error(result: Result(a, e)) -> Result(a, Nil) {
+ map_error(result, fn(_) { Nil })
+ }
-/// Returns the first value if it is Ok, otherwise return the second value.
-///
-/// ## Examples
-///
-/// > or(Ok(1), Ok(2))
-/// Ok(1)
-///
-/// > or(Ok(1), Error("Error 2"))
-/// Ok(1)
-///
-/// > or(Error("Error 1"), Ok(2))
-/// Ok(2)
-///
-/// > or(Error("Error 1"), Error("Error 2"))
-/// Error("Error 2")
-///
-pub fn or(first: Result(a, e), second: Result(a, e)) -> Result(a, e) {
- case first {
- Ok(_) -> first
- Error(_) -> second
+ /// Returns the first value if it is Ok, otherwise return the second value.
+ ///
+ /// ## Examples
+ ///
+ /// > or(Ok(1), Ok(2))
+ /// Ok(1)
+ ///
+ /// > or(Ok(1), Error("Error 2"))
+ /// Ok(1)
+ ///
+ /// > or(Error("Error 1"), Ok(2))
+ /// Ok(2)
+ ///
+ /// > or(Error("Error 1"), Error("Error 2"))
+ /// Error("Error 2")
+ ///
+ pub fn or(first: Result(a, e), second: Result(a, e)) -> Result(a, e) {
+ case first {
+ Ok(_) -> first
+ Error(_) -> second
+ }
}
-}
-/// Returns the first value if it is Ok, otherwise evaluates the given function for a fallback value.
-///
-/// ## Examples
-///
-/// > or(Ok(1), Ok(2))
-/// Ok(1)
-///
-/// > or(Ok(1), Error("Error 2"))
-/// Ok(1)
-///
-/// > or(Error("Error 1"), Ok(2))
-/// Ok(2)
-///
-/// > or(Error("Error 1"), Error("Error 2"))
-/// Error("Error 2")
-///
-pub fn lazy_or(
- first: Result(a, e),
- second: fn() -> Result(a, e),
-) -> Result(a, e) {
- case first {
- Ok(_) -> first
- Error(_) -> second()
+ /// Returns the first value if it is Ok, otherwise evaluates the given function for a fallback value.
+ ///
+ /// ## Examples
+ ///
+ /// > or(Ok(1), Ok(2))
+ /// Ok(1)
+ ///
+ /// > or(Ok(1), Error("Error 2"))
+ /// Ok(1)
+ ///
+ /// > or(Error("Error 1"), Ok(2))
+ /// Ok(2)
+ ///
+ /// > or(Error("Error 1"), Error("Error 2"))
+ /// Error("Error 2")
+ ///
+ pub fn lazy_or(
+ first: Result(a, e),
+ second: fn() -> Result(a, e),
+ ) -> Result(a, e) {
+ case first {
+ Ok(_) -> first
+ Error(_) -> second()
+ }
}
-}
-/// Combines a list of results into a single result.
-/// If all elements in the list are Ok then returns an Ok holding the list of values.
-/// If any element is Error then returns the first error.
-///
-/// ## Examples
-/// > all([Ok(1), Ok(2)])
-/// Ok([1, 2])
-///
-/// > all([Ok(1), Error("e")])
-/// Error("e")
-pub fn all(results: List(Result(a, e))) -> Result(List(a), e) {
- list.try_map(results, fn(x) { x })
-}
+ /// Combines a list of results into a single result.
+ /// If all elements in the list are Ok then returns an Ok holding the list of values.
+ /// If any element is Error then returns the first error.
+ ///
+ /// ## Examples
+ /// > all([Ok(1), Ok(2)])
+ /// Ok([1, 2])
+ ///
+ /// > all([Ok(1), Error("e")])
+ /// Error("e")
+ pub fn all(results: List(Result(a, e))) -> Result(List(a), e) {
+ list.try_map(results, fn(x) { x })
+ }
-pub fn replace_error(result: Result(a, e1), error: e2) -> Result(a, e2) {
- result
- |> map_error(fn(_) { error })
-}
+ pub fn replace_error(result: Result(a, e1), error: e2) -> Result(a, e2) {
+ result
+ |> map_error(fn(_) { error })
+ }
-/// Given a list of results
-/// Return only the values inside Ok
-///
-/// ## Examples
-///
-/// ```
-/// > values([Ok(1), None, Ok(3)])
-/// [1, 3]
-/// ```
-///
-pub fn values(results: List(Result(a, e))) -> List(a) {
- list.filter_map(results, fn(r) { r })
+ /// Given a list of results
+ /// Return only the values inside Ok
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > values([Ok(1), None, Ok(3)])
+ /// [1, 3]
+ /// ```
+ ///
+ pub fn values(results: List(Result(a, e))) -> List(a) {
+ list.filter_map(results, fn(r) { r })
+ }
}
diff --git a/src/gleam/set.gleam b/src/gleam/set.gleam
index 61bb47a..86c3ccb 100644
--- a/src/gleam/set.gleam
+++ b/src/gleam/set.gleam
@@ -1,207 +1,215 @@
-import gleam/map.{Map}
-import gleam/result
-import gleam/list
+if erlang {
+ import gleam/map.{Map}
+ import gleam/result
+ import gleam/list
-/// A set is a collection of unique members of the same type.
-///
-/// It is implemented using the `gleam/map` module, so inserts and lookups have
-/// logarithmic time complexity.
-///
-pub opaque type Set(member) {
- // A list is used as the map value as an empty list has the smallest
- // representation in Erlang's binary format
- Set(map: Map(member, List(Nil)))
-}
+ /// A set is a collection of unique members of the same type.
+ ///
+ /// It is implemented using the `gleam/map` module, so inserts and lookups have
+ /// logarithmic time complexity.
+ ///
+ pub opaque type Set(member) {
+ // A list is used as the map value as an empty list has the smallest
+ // representation in Erlang's binary format
+ Set(map: Map(member, List(Nil)))
+ }
-/// Creates a new empty set.
-///
-pub fn new() -> Set(member) {
- Set(map.new())
-}
+ /// Creates a new empty set.
+ ///
+ pub fn new() -> Set(member) {
+ Set(map.new())
+ }
-/// Gets the number of members in a set.
-///
-/// This function runs in constant time.
-///
-/// ## Examples
-///
-/// > new() |> insert(1) |> insert(2) |> size
-/// 2
-///
-pub fn size(set: Set(member)) -> Int {
- map.size(set.map)
-}
+ /// Gets the number of members in a set.
+ ///
+ /// This function runs in constant time.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> insert(1) |> insert(2) |> size
+ /// 2
+ ///
+ pub fn size(set: Set(member)) -> Int {
+ map.size(set.map)
+ }
-/// Inserts an member into the set.
-///
-/// This function runs in logarithmic time.
-///
-/// ## Examples
-///
-/// > new() |> insert(1) |> insert(2) |> size
-/// 2
-///
-pub fn insert(into set: Set(member), this member: member) -> Set(member) {
- Set(map: map.insert(set.map, member, []))
-}
+ /// Inserts an member into the set.
+ ///
+ /// This function runs in logarithmic time.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> insert(1) |> insert(2) |> size
+ /// 2
+ ///
+ pub fn insert(into set: Set(member), this member: member) -> Set(member) {
+ Set(map: map.insert(set.map, member, []))
+ }
-/// Checks whether a set contains a given member.
-///
-/// This function runs in logarithmic time.
-///
-/// ## Examples
-///
-/// > new() |> insert(2) |> contains(2)
-/// True
-///
-/// > new() |> insert(2) |> contains(1)
-/// False
-///
-pub fn contains(in set: Set(member), this member: member) -> Bool {
- set.map
- |> map.get(member)
- |> result.is_ok
-}
+ /// Checks whether a set contains a given member.
+ ///
+ /// This function runs in logarithmic time.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> insert(2) |> contains(2)
+ /// True
+ ///
+ /// > new() |> insert(2) |> contains(1)
+ /// False
+ ///
+ pub fn contains(in set: Set(member), this member: member) -> Bool {
+ set.map
+ |> map.get(member)
+ |> result.is_ok
+ }
-/// Removes an member from a set. If the set does not contain the member then
-/// the set is returned unchanged.
-///
-/// This function runs in logarithmic time.
-///
-/// ## Examples
-///
-/// > new() |> insert(2) |> delete(2) |> contains(1)
-/// False
-///
-pub fn delete(from set: Set(member), this member: member) -> Set(member) {
- Set(map: map.delete(set.map, member))
-}
+ /// Removes an member from a set. If the set does not contain the member then
+ /// the set is returned unchanged.
+ ///
+ /// This function runs in logarithmic time.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> insert(2) |> delete(2) |> contains(1)
+ /// False
+ ///
+ pub fn delete(from set: Set(member), this member: member) -> Set(member) {
+ Set(map: map.delete(set.map, member))
+ }
-/// Converts the set into a list of the contained members.
-///
-/// The list has no specific ordering, any unintentional ordering may change in
-/// future versions of Gleam or Erlang.
-///
-/// This function runs in linear time.
-///
-/// ## Examples
-///
-/// > new() |> insert(2) |> to_list
-/// [2]
-///
-pub fn to_list(set: Set(member)) -> List(member) {
- map.keys(set.map)
-}
+ /// Converts the set into a list of the contained members.
+ ///
+ /// The list has no specific ordering, any unintentional ordering may change in
+ /// future versions of Gleam or Erlang.
+ ///
+ /// This function runs in linear time.
+ ///
+ /// ## Examples
+ ///
+ /// > new() |> insert(2) |> to_list
+ /// [2]
+ ///
+ pub fn to_list(set: Set(member)) -> List(member) {
+ map.keys(set.map)
+ }
-/// Creates a new set of the members in a given list.
-///
-/// This function runs in loglinear time.
-///
-/// ## Examples
-///
-/// > import gleam/list
-/// > [1, 1, 2, 4, 3, 2] |> from_list |> to_list |> list.sort
-/// [1, 3, 3, 4]
-///
-pub fn from_list(members: List(member)) -> Set(member) {
- let map =
- list.fold(
- over: members,
- from: map.new(),
- with: fn(k, m) { map.insert(m, k, []) },
- )
- Set(map)
-}
+ /// Creates a new set of the members in a given list.
+ ///
+ /// This function runs in loglinear time.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/list
+ /// > [1, 1, 2, 4, 3, 2] |> from_list |> to_list |> list.sort
+ /// [1, 3, 3, 4]
+ ///
+ pub fn from_list(members: List(member)) -> Set(member) {
+ let map =
+ list.fold(
+ over: members,
+ from: map.new(),
+ with: fn(k, m) { map.insert(m, k, []) },
+ )
+ Set(map)
+ }
-/// Combines all entries into a single value by calling a given function on each
-/// one.
-///
-/// Sets are not ordered so the values are not returned in any specific order.
-/// Do not write code that relies on the order entries are used by this
-/// function as it may change in later versions of Gleam or Erlang.
-///
-/// # Examples
-///
-/// > from_list([1, 3, 9])
-/// > |> fold(0, fn(member, accumulator) { accumulator + member })
-/// 13
-///
-pub fn fold(
- over set: Set(member),
- from initial: acc,
- with reducer: fn(member, acc) -> acc,
-) -> acc {
- map.fold(over: set.map, from: initial, with: fn(k, _, a) { reducer(k, a) })
-}
+ /// Combines all entries into a single value by calling a given function on each
+ /// one.
+ ///
+ /// Sets are not ordered so the values are not returned in any specific order.
+ /// Do not write code that relies on the order entries are used by this
+ /// function as it may change in later versions of Gleam or Erlang.
+ ///
+ /// # Examples
+ ///
+ /// > from_list([1, 3, 9])
+ /// > |> fold(0, fn(member, accumulator) { accumulator + member })
+ /// 13
+ ///
+ pub fn fold(
+ over set: Set(member),
+ from initial: acc,
+ with reducer: fn(member, acc) -> acc,
+ ) -> acc {
+ map.fold(over: set.map, from: initial, with: fn(k, _, a) { reducer(k, a) })
+ }
-/// Creates a new set from an existing set, minus any members that a given
-/// function returns False for.
-///
-/// This function runs in loglinear time.
-///
-/// ## Examples
-///
-/// > import gleam/int
-/// > from_list([1, 4, 6, 3, 675, 44, 67])
-/// > |> filter(for: int.is_even)
-/// > |> to_list
-/// [4, 6, 44]
-///
-pub fn filter(
- in set: Set(member),
- for property: fn(member) -> Bool,
-) -> Set(member) {
- Set(map.filter(in: set.map, for: fn(m, _) { property(m) }))
-}
+ /// Creates a new set from an existing set, minus any members that a given
+ /// function returns False for.
+ ///
+ /// This function runs in loglinear time.
+ ///
+ /// ## Examples
+ ///
+ /// > import gleam/int
+ /// > from_list([1, 4, 6, 3, 675, 44, 67])
+ /// > |> filter(for: int.is_even)
+ /// > |> to_list
+ /// [4, 6, 44]
+ ///
+ pub fn filter(
+ in set: Set(member),
+ for property: fn(member) -> Bool,
+ ) -> Set(member) {
+ Set(map.filter(in: set.map, for: fn(m, _) { property(m) }))
+ }
-/// Creates a new map from a given map, only including any members which are in
-/// a given list.
-///
-/// This function runs in loglinear time.
-///
-/// ## Examples
-///
-/// > from_list([1, 2, 3]) |> take([1, 3, 5]) |> to_list
-/// [1, 3]
-///
-pub fn take(from set: Set(member), keeping desired: List(member)) -> Set(member) {
- Set(map.take(from: set.map, keeping: desired))
-}
+ /// Creates a new map from a given map, only including any members which are in
+ /// a given list.
+ ///
+ /// This function runs in loglinear time.
+ ///
+ /// ## Examples
+ ///
+ /// > from_list([1, 2, 3]) |> take([1, 3, 5]) |> to_list
+ /// [1, 3]
+ ///
+ pub fn take(
+ from set: Set(member),
+ keeping desired: List(member),
+ ) -> Set(member) {
+ Set(map.take(from: set.map, keeping: desired))
+ }
-fn order(first: Set(member), second: Set(member)) -> #(Set(member), Set(member)) {
- case map.size(first.map) > map.size(second.map) {
- True -> #(first, second)
- False -> #(second, first)
+ fn order(
+ first: Set(member),
+ second: Set(member),
+ ) -> #(Set(member), Set(member)) {
+ case map.size(first.map) > map.size(second.map) {
+ True -> #(first, second)
+ False -> #(second, first)
+ }
}
-}
-/// Creates a new set that contains all members of both given sets.
-///
-/// This function runs in loglinear time.
-///
-/// ## Examples
-///
-/// > union(from_list([1, 2]), from_list([2, 3])) |> to_list
-/// [1, 2, 3]
-///
-pub fn union(of first: Set(member), and second: Set(member)) -> Set(member) {
- let #(larger, smaller) = order(first, second)
- fold(over: smaller, from: larger, with: fn(m, a) { insert(a, m) })
-}
+ /// Creates a new set that contains all members of both given sets.
+ ///
+ /// This function runs in loglinear time.
+ ///
+ /// ## Examples
+ ///
+ /// > union(from_list([1, 2]), from_list([2, 3])) |> to_list
+ /// [1, 2, 3]
+ ///
+ pub fn union(of first: Set(member), and second: Set(member)) -> Set(member) {
+ let #(larger, smaller) = order(first, second)
+ fold(over: smaller, from: larger, with: fn(m, a) { insert(a, m) })
+ }
-/// Creates a new set that contains members that are present in both given sets.
-///
-/// This function runs in loglinear time.
-///
-/// ## Examples
-///
-/// > intersection(from_list([1, 2]), from_list([2, 3])) |> to_list
-/// [2]
-///
-pub fn intersection(
- of first: Set(member),
- and second: Set(member),
-) -> Set(member) {
- let #(larger, smaller) = order(first, second)
- take(from: larger, keeping: to_list(smaller))
+ /// Creates a new set that contains members that are present in both given sets.
+ ///
+ /// This function runs in loglinear time.
+ ///
+ /// ## Examples
+ ///
+ /// > intersection(from_list([1, 2]), from_list([2, 3])) |> to_list
+ /// [2]
+ ///
+ pub fn intersection(
+ of first: Set(member),
+ and second: Set(member),
+ ) -> Set(member) {
+ let #(larger, smaller) = order(first, second)
+ take(from: larger, keeping: to_list(smaller))
+ }
}
diff --git a/src/gleam/should.gleam b/src/gleam/should.gleam
index 0a4b04b..b7c739b 100644
--- a/src/gleam/should.gleam
+++ b/src/gleam/should.gleam
@@ -4,32 +4,54 @@
//// More information on running eunit can be found in [the rebar3
//// documentation](https://rebar3.org/docs/testing/eunit/).
-// TODO: Move this module into another package so it can be used as a
-// dep only in test.
-pub external type Expectation
+if erlang {
+ // TODO: Move this module into another package so it can be used as a
+ // dep only in test.
+ pub external fn equal(a, a) -> Nil =
+ "gleam_stdlib" "should_equal"
-pub external fn equal(a, a) -> Expectation =
- "gleam_stdlib" "should_equal"
+ pub external fn not_equal(a, a) -> Nil =
+ "gleam_stdlib" "should_not_equal"
-pub external fn not_equal(a, a) -> Expectation =
- "gleam_stdlib" "should_not_equal"
+ pub external fn be_ok(Result(a, b)) -> Nil =
+ "gleam_stdlib" "should_be_ok"
-pub fn be_true(actual: Bool) -> Expectation {
+ pub external fn be_error(Result(a, b)) -> Nil =
+ "gleam_stdlib" "should_be_error"
+}
+
+if javascript {
+ pub fn equal(a, b) {
+ assert True = a == b
+ Nil
+ }
+
+ pub fn not_equal(a, b) {
+ assert True = a != b
+ Nil
+ }
+
+ pub fn be_ok(a) {
+ assert Ok(_) = a
+ Nil
+ }
+
+ pub fn be_error(a) {
+ assert Error(_) = a
+ Nil
+ }
+}
+
+pub fn be_true(actual: Bool) -> Nil {
actual
|> equal(True)
}
-pub fn be_false(actual: Bool) -> Expectation {
+pub fn be_false(actual: Bool) -> Nil {
actual
|> equal(False)
}
-pub external fn be_ok(Result(a, b)) -> Expectation =
- "gleam_stdlib" "should_be_ok"
-
-pub external fn be_error(Result(a, b)) -> Expectation =
- "gleam_stdlib" "should_be_error"
-
-pub fn fail() -> Expectation {
+pub fn fail() -> Nil {
be_true(False)
}
diff --git a/src/gleam/string.gleam b/src/gleam/string.gleam
index ce7cd64..a4574dc 100644
--- a/src/gleam/string.gleam
+++ b/src/gleam/string.gleam
@@ -1,476 +1,482 @@
//// Strings in Gleam are UTF-8 binaries. They can be written in your code a
//// text surrounded by `"double quotes"`.
-import gleam/string_builder
-import gleam/dynamic.{Dynamic}
-import gleam/iterator
-import gleam/list
-import gleam/order
-import gleam/result
-
-pub type String =
- String
-
-/// A UtfCodepoint is the integer representation of a valid UTF codepoint
-pub type UtfCodepoint =
- UtfCodepoint
-
-/// Determines if a string is empty.
-///
-/// ## Examples
-///
-/// > is_empty("")
-/// True
-///
-/// > is_empty("the world")
-/// False
-///
-pub fn is_empty(str: String) -> Bool {
- str == ""
-}
+if erlang {
+ import gleam/string_builder
+ import gleam/dynamic.{Dynamic}
+ import gleam/iterator
+ import gleam/list
+ import gleam/order
+ import gleam/result
+
+ pub type String =
+ String
+
+ /// A UtfCodepoint is the integer representation of a valid UTF codepoint
+ pub type UtfCodepoint =
+ UtfCodepoint
+
+ /// Determines if a string is empty.
+ ///
+ /// ## Examples
+ ///
+ /// > is_empty("")
+ /// True
+ ///
+ /// > is_empty("the world")
+ /// False
+ ///
+ pub fn is_empty(str: String) -> Bool {
+ str == ""
+ }
-/// Gets the number of grapheme clusters in a given string.
-///
-/// This function has to iterate across the whole string to count the number of
-/// graphemes, so it runs in linear time.
-///
-/// ## Examples
-///
-/// > length("Gleam")
-/// 5
-///
-/// > length("ß↑e̊")
-/// 3
-///
-/// > length("")
-/// 0
-///
-pub external fn length(String) -> Int =
- "string" "length"
-
-///
-/// Reverses a string.
-///
-/// This function has to iterate across the whole string so it runs in linear
-/// time.
-///
-/// ## Examples
-///
-/// > reverse("stressed")
-/// "desserts"
-///
-pub fn reverse(string: String) -> String {
- string
- |> string_builder.from_string
- |> string_builder.reverse
- |> string_builder.to_string
-}
+ /// Gets the number of grapheme clusters in a given string.
+ ///
+ /// This function has to iterate across the whole string to count the number of
+ /// graphemes, so it runs in linear time.
+ ///
+ /// ## Examples
+ ///
+ /// > length("Gleam")
+ /// 5
+ ///
+ /// > length("ß↑e̊")
+ /// 3
+ ///
+ /// > length("")
+ /// 0
+ ///
+ pub external fn length(String) -> Int =
+ "string" "length"
+
+ ///
+ /// Reverses a string.
+ ///
+ /// This function has to iterate across the whole string so it runs in linear
+ /// time.
+ ///
+ /// ## Examples
+ ///
+ /// > reverse("stressed")
+ /// "desserts"
+ ///
+ pub fn reverse(string: String) -> String {
+ string
+ |> string_builder.from_string
+ |> string_builder.reverse
+ |> string_builder.to_string
+ }
-/// Creates a new string by replacing all occurrences of a given substring.
-///
-/// ## Examples
-///
-/// > replace("www.example.com", each: ".", with: "-")
-/// "www-example-com"
-///
-/// > replace("a,b,c,d,e", each: ",", with: "/")
-/// "a/b/c/d/e"
-///
-pub fn replace(
- in string: String,
- each pattern: String,
- with substitute: String,
-) -> String {
- string
- |> string_builder.from_string
- |> string_builder.replace(each: pattern, with: substitute)
- |> string_builder.to_string
-}
+ /// Creates a new string by replacing all occurrences of a given substring.
+ ///
+ /// ## Examples
+ ///
+ /// > replace("www.example.com", each: ".", with: "-")
+ /// "www-example-com"
+ ///
+ /// > replace("a,b,c,d,e", each: ",", with: "/")
+ /// "a/b/c/d/e"
+ ///
+ pub fn replace(
+ in string: String,
+ each pattern: String,
+ with substitute: String,
+ ) -> String {
+ string
+ |> string_builder.from_string
+ |> string_builder.replace(each: pattern, with: substitute)
+ |> string_builder.to_string
+ }
-/// Creates a new string with all the graphemes in the input string converted to
-/// lowercase.
-///
-/// Useful for case-insensitive comparisons.
-///
-/// ## Examples
-///
-/// > lowercase("X-FILES")
-/// "x-files"
-///
-pub external fn lowercase(String) -> String =
- "string" "lowercase"
-
-/// Creates a new string with all the graphemes in the input string converted to
-/// uppercase.
-///
-/// Useful for case-insensitive comparisons and VIRTUAL YELLING.
-///
-/// ## Examples
-///
-/// > uppercase("skinner")
-/// "SKINNER"
-///
-pub external fn uppercase(String) -> String =
- "string" "uppercase"
-
-/// Compares two strings to see which is "larger" by comparing their graphemes.
-///
-/// This does not compare the size or length of the given strings.
-///
-/// ## Examples
-///
-/// > compare("Anthony", "Anthony")
-/// order.Eq
-///
-/// > compare("A", "B")
-/// order.Lt
-///
-pub external fn compare(String, String) -> order.Order =
- "gleam_stdlib" "compare_strings"
-
-external fn erl_slice(String, Int, Int) -> String =
- "string" "slice"
-
-/// Takes a substring given a start and end Grapheme indexes. Negative indexes
-/// are taken starting from the *end* of the list.
-///
-/// ## Examples
-/// > slice(from: "gleam", at_index: 1, length: 2)
-/// "le"
-///
-/// > slice(from: "gleam", at_index: 1, length: 10)
-/// "leam"
-///
-/// > slice(from: "gleam", at_index: 10, length: 3)
-/// ""
-///
-/// > slice(from: "gleam", at_index: -2, length: 2)
-/// "am"
-///
-/// > slice(from: "gleam", at_index: -12, length: 2)
-/// ""
-///
-pub fn slice(from string: String, at_index idx: Int, length len: Int) -> String {
- case len < 0 {
- True -> ""
- False ->
- case idx < 0 {
- True -> {
- let translated_idx = length(string) + idx
- case translated_idx < 0 {
- True -> ""
- False -> erl_slice(string, translated_idx, len)
+ /// Creates a new string with all the graphemes in the input string converted to
+ /// lowercase.
+ ///
+ /// Useful for case-insensitive comparisons.
+ ///
+ /// ## Examples
+ ///
+ /// > lowercase("X-FILES")
+ /// "x-files"
+ ///
+ pub external fn lowercase(String) -> String =
+ "string" "lowercase"
+
+ /// Creates a new string with all the graphemes in the input string converted to
+ /// uppercase.
+ ///
+ /// Useful for case-insensitive comparisons and VIRTUAL YELLING.
+ ///
+ /// ## Examples
+ ///
+ /// > uppercase("skinner")
+ /// "SKINNER"
+ ///
+ pub external fn uppercase(String) -> String =
+ "string" "uppercase"
+
+ /// Compares two strings to see which is "larger" by comparing their graphemes.
+ ///
+ /// This does not compare the size or length of the given strings.
+ ///
+ /// ## Examples
+ ///
+ /// > compare("Anthony", "Anthony")
+ /// order.Eq
+ ///
+ /// > compare("A", "B")
+ /// order.Lt
+ ///
+ pub external fn compare(String, String) -> order.Order =
+ "gleam_stdlib" "compare_strings"
+
+ external fn erl_slice(String, Int, Int) -> String =
+ "string" "slice"
+
+ /// Takes a substring given a start and end Grapheme indexes. Negative indexes
+ /// are taken starting from the *end* of the list.
+ ///
+ /// ## Examples
+ /// > slice(from: "gleam", at_index: 1, length: 2)
+ /// "le"
+ ///
+ /// > slice(from: "gleam", at_index: 1, length: 10)
+ /// "leam"
+ ///
+ /// > slice(from: "gleam", at_index: 10, length: 3)
+ /// ""
+ ///
+ /// > slice(from: "gleam", at_index: -2, length: 2)
+ /// "am"
+ ///
+ /// > slice(from: "gleam", at_index: -12, length: 2)
+ /// ""
+ ///
+ pub fn slice(
+ from string: String,
+ at_index idx: Int,
+ length len: Int,
+ ) -> String {
+ case len < 0 {
+ True -> ""
+ False ->
+ case idx < 0 {
+ True -> {
+ let translated_idx = length(string) + idx
+ case translated_idx < 0 {
+ True -> ""
+ False -> erl_slice(string, translated_idx, len)
+ }
}
+ False -> erl_slice(string, idx, len)
}
- False -> erl_slice(string, idx, len)
- }
+ }
}
-}
-/// Drops contents of the first string that occur before the second string.
-/// If the first string does not contain the second string, the first string is returned.
-///
-/// ## Examples
-/// > crop(from: "The Lone Gunmen", before: "Lone")
-/// "Lone Gunmen"
-///
-pub fn crop(from string: String, before substring: String) -> String {
- string
- |> erl_contains(substring)
- |> dynamic.string()
- |> result.unwrap(string)
-}
+ /// Drops contents of the first string that occur before the second string.
+ /// If the first string does not contain the second string, the first string is returned.
+ ///
+ /// ## Examples
+ /// > crop(from: "The Lone Gunmen", before: "Lone")
+ /// "Lone Gunmen"
+ ///
+ pub fn crop(from string: String, before substring: String) -> String {
+ string
+ |> erl_contains(substring)
+ |> dynamic.string()
+ |> result.unwrap(string)
+ }
-/// Drops *n* Graphemes from the left side of a string.
-///
-/// ## Examples
-/// > drop_left(from: "The Lone Gunmen", up_to: 2)
-/// "e Lone Gunmen"
-///
-pub fn drop_left(from string: String, up_to num_graphemes: Int) -> String {
- case num_graphemes < 0 {
- True -> string
- False -> slice(string, num_graphemes, length(string) - num_graphemes)
+ /// Drops *n* Graphemes from the left side of a string.
+ ///
+ /// ## Examples
+ /// > drop_left(from: "The Lone Gunmen", up_to: 2)
+ /// "e Lone Gunmen"
+ ///
+ pub fn drop_left(from string: String, up_to num_graphemes: Int) -> String {
+ case num_graphemes < 0 {
+ True -> string
+ False -> slice(string, num_graphemes, length(string) - num_graphemes)
+ }
}
-}
-/// Drops *n* Graphemes from the right side of a string.
-///
-/// ## Examples
-/// > drop_right(from: "Cigarette Smoking Man", up_to: 2)
-/// "Cigarette Smoking M"
-///
-pub fn drop_right(from string: String, up_to num_graphemes: Int) -> String {
- case num_graphemes < 0 {
- True -> string
- False -> slice(string, 0, length(string) - num_graphemes)
+ /// Drops *n* Graphemes from the right side of a string.
+ ///
+ /// ## Examples
+ /// > drop_right(from: "Cigarette Smoking Man", up_to: 2)
+ /// "Cigarette Smoking M"
+ ///
+ pub fn drop_right(from string: String, up_to num_graphemes: Int) -> String {
+ case num_graphemes < 0 {
+ True -> string
+ False -> slice(string, 0, length(string) - num_graphemes)
+ }
}
-}
-external fn erl_contains(String, String) -> Dynamic =
- "string" "find"
-
-/// Checks if the first string contains the second.
-///
-/// ## Examples
-///
-/// > contains(does: "theory", contain: "ory")
-/// True
-///
-/// > contains(does: "theory", contain: "the")
-/// True
-///
-/// > contains(does: "theory", contain: "THE")
-/// False
-///
-pub fn contains(does haystack: String, contain needle: String) -> Bool {
- haystack
- |> erl_contains(needle)
- |> dynamic.atom
- |> result.is_error
-}
+ external fn erl_contains(String, String) -> Dynamic =
+ "string" "find"
+
+ /// Checks if the first string contains the second.
+ ///
+ /// ## Examples
+ ///
+ /// > contains(does: "theory", contain: "ory")
+ /// True
+ ///
+ /// > contains(does: "theory", contain: "the")
+ /// True
+ ///
+ /// > contains(does: "theory", contain: "THE")
+ /// False
+ ///
+ pub fn contains(does haystack: String, contain needle: String) -> Bool {
+ haystack
+ |> erl_contains(needle)
+ |> dynamic.atom
+ |> result.is_error
+ }
-/// Checks whether the first string starts with the second one.
-///
-/// ## Examples
-///
-/// > starts_with("theory", "ory")
-/// False
-///
-pub external fn starts_with(String, String) -> Bool =
- "gleam_stdlib" "string_starts_with"
-
-/// Checks whether the first string ends with the second one.
-///
-/// ## Examples
-///
-/// > ends_with("theory", "ory")
-/// True
-///
-pub external fn ends_with(String, String) -> Bool =
- "gleam_stdlib" "string_ends_with"
-
-/// Creates a list of strings by splitting a given string on a given substring.
-///
-/// ## Examples
-///
-/// > split("home/gleam/desktop/", on: "/")
-/// ["home", "gleam", "desktop", ""]
-///
-pub fn split(x: String, on substring: String) -> List(String) {
- x
- |> string_builder.from_string
- |> string_builder.split(on: substring)
- |> list.map(with: string_builder.to_string)
-}
+ /// Checks whether the first string starts with the second one.
+ ///
+ /// ## Examples
+ ///
+ /// > starts_with("theory", "ory")
+ /// False
+ ///
+ pub external fn starts_with(String, String) -> Bool =
+ "gleam_stdlib" "string_starts_with"
+
+ /// Checks whether the first string ends with the second one.
+ ///
+ /// ## Examples
+ ///
+ /// > ends_with("theory", "ory")
+ /// True
+ ///
+ pub external fn ends_with(String, String) -> Bool =
+ "gleam_stdlib" "string_ends_with"
+
+ /// Creates a list of strings by splitting a given string on a given substring.
+ ///
+ /// ## Examples
+ ///
+ /// > split("home/gleam/desktop/", on: "/")
+ /// ["home", "gleam", "desktop", ""]
+ ///
+ pub fn split(x: String, on substring: String) -> List(String) {
+ x
+ |> string_builder.from_string
+ |> string_builder.split(on: substring)
+ |> list.map(with: string_builder.to_string)
+ }
-external fn erl_split(String, String) -> List(String) =
- "string" "split"
-
-/// Splits a string a single time on the given substring.
-///
-/// Returns an error if substring not present.
-///
-/// ## Examples
-///
-/// > split_once("home/gleam/desktop/", on: "/")
-/// Ok(#("home", "gleam/desktop/"))
-///
-/// > split_once("home/gleam/desktop/", on: "?")
-/// Error(Nil)
-///
-pub fn split_once(
- x: String,
- on substring: String,
-) -> Result(#(String, String), Nil) {
- case erl_split(x, substring) {
- [first, rest] -> Ok(#(first, rest))
- _ -> Error(Nil)
+ external fn erl_split(String, String) -> List(String) =
+ "string" "split"
+
+ /// Splits a string a single time on the given substring.
+ ///
+ /// Returns an error if substring not present.
+ ///
+ /// ## Examples
+ ///
+ /// > split_once("home/gleam/desktop/", on: "/")
+ /// Ok(#("home", "gleam/desktop/"))
+ ///
+ /// > split_once("home/gleam/desktop/", on: "?")
+ /// Error(Nil)
+ ///
+ pub fn split_once(
+ x: String,
+ on substring: String,
+ ) -> Result(#(String, String), Nil) {
+ case erl_split(x, substring) {
+ [first, rest] -> Ok(#(first, rest))
+ _ -> Error(Nil)
+ }
}
-}
-/// Creates a new string by joining two strings together.
-///
-/// This function copies both strings and runs in linear time. If you find
-/// yourself joining strings frequently consider using the [string_builder](../string_builder)
-/// module as it can append strings much faster!
-///
-/// ## Examples
-///
-/// > append(to: "butter", suffix: "fly")
-/// "butterfly"
-///
-pub fn append(to first: String, suffix second: String) -> String {
- first
- |> string_builder.from_string
- |> string_builder.append(second)
- |> string_builder.to_string
-}
+ /// Creates a new string by joining two strings together.
+ ///
+ /// This function copies both strings and runs in linear time. If you find
+ /// yourself joining strings frequently consider using the [string_builder](../string_builder)
+ /// module as it can append strings much faster!
+ ///
+ /// ## Examples
+ ///
+ /// > append(to: "butter", suffix: "fly")
+ /// "butterfly"
+ ///
+ pub fn append(to first: String, suffix second: String) -> String {
+ first
+ |> string_builder.from_string
+ |> string_builder.append(second)
+ |> string_builder.to_string
+ }
-/// Creates a new string by joining many strings together.
-///
-/// This function copies both strings and runs in linear time. If you find
-/// yourself joining strings frequently consider using the [string_builder](../string_builder)
-/// module as it can append strings much faster!
-///
-/// ## Examples
-///
-/// > concat(["never", "the", "less"])
-/// "nevertheless"
-///
-pub fn concat(strings: List(String)) -> String {
- strings
- |> string_builder.from_strings
- |> string_builder.to_string
-}
+ /// Creates a new string by joining many strings together.
+ ///
+ /// This function copies both strings and runs in linear time. If you find
+ /// yourself joining strings frequently consider using the [string_builder](../string_builder)
+ /// module as it can append strings much faster!
+ ///
+ /// ## Examples
+ ///
+ /// > concat(["never", "the", "less"])
+ /// "nevertheless"
+ ///
+ pub fn concat(strings: List(String)) -> String {
+ strings
+ |> string_builder.from_strings
+ |> string_builder.to_string
+ }
-/// Creates a new string by repeating a string a given number of times.
-///
-/// This function runs in linear time.
-///
-/// ## Examples
-///
-/// > repeat("ha", times: 3)
-/// "hahaha"
-///
-pub fn repeat(string: String, times times: Int) -> String {
- iterator.repeat(string)
- |> iterator.take(times)
- |> iterator.to_list
- |> concat
-}
+ /// Creates a new string by repeating a string a given number of times.
+ ///
+ /// This function runs in linear time.
+ ///
+ /// ## Examples
+ ///
+ /// > repeat("ha", times: 3)
+ /// "hahaha"
+ ///
+ pub fn repeat(string: String, times times: Int) -> String {
+ iterator.repeat(string)
+ |> iterator.take(times)
+ |> iterator.to_list
+ |> concat
+ }
-/// Joins many strings together with a given separator.
-///
-/// This function runs in linear time.
-///
-/// ## Examples
-///
-/// > join(["home","evan","Desktop"], with: "/")
-/// "home/evan/Desktop"
-///
-pub fn join(strings: List(String), with separator: String) -> String {
- strings
- |> list.intersperse(with: separator)
- |> concat
-}
+ /// Joins many strings together with a given separator.
+ ///
+ /// This function runs in linear time.
+ ///
+ /// ## Examples
+ ///
+ /// > join(["home","evan","Desktop"], with: "/")
+ /// "home/evan/Desktop"
+ ///
+ pub fn join(strings: List(String), with separator: String) -> String {
+ strings
+ |> list.intersperse(with: separator)
+ |> concat
+ }
-type Direction {
- Leading
- Trailing
- Both
-}
+ type Direction {
+ Leading
+ Trailing
+ Both
+ }
-external fn erl_pad(String, Int, Direction, String) -> String =
- "gleam_stdlib" "string_pad"
-
-/// Pads a string on the left until it has at least given number of Graphemes.
-///
-/// ## Examples
-///
-/// > pad_left("121", to: 5, with: ".")
-/// "..121"
-///
-/// > pad_left("121", to: 3, with: ".")
-/// "121"
-///
-/// > pad_left("121", to: 2, with: ".")
-/// "121"
-///
-pub fn pad_left(string: String, to length: Int, with pad_string: String) {
- erl_pad(string, length, Leading, pad_string)
-}
+ external fn erl_pad(String, Int, Direction, String) -> String =
+ "gleam_stdlib" "string_pad"
+
+ /// Pads a string on the left until it has at least given number of Graphemes.
+ ///
+ /// ## Examples
+ ///
+ /// > pad_left("121", to: 5, with: ".")
+ /// "..121"
+ ///
+ /// > pad_left("121", to: 3, with: ".")
+ /// "121"
+ ///
+ /// > pad_left("121", to: 2, with: ".")
+ /// "121"
+ ///
+ pub fn pad_left(string: String, to length: Int, with pad_string: String) {
+ erl_pad(string, length, Leading, pad_string)
+ }
-/// Pads a string on the right until it has a given length.
-///
-/// ## Examples
-///
-/// > pad_right("121", to: 5, with: ".")
-/// "121.."
-///
-/// > pad_right("121", to: 3, with: ".")
-/// "121"
-///
-/// > pad_right("121", to: 2, with: ".")
-/// "121"
-///
-pub fn pad_right(string: String, to length: Int, with pad_string: String) {
- erl_pad(string, length, Trailing, pad_string)
-}
+ /// Pads a string on the right until it has a given length.
+ ///
+ /// ## Examples
+ ///
+ /// > pad_right("121", to: 5, with: ".")
+ /// "121.."
+ ///
+ /// > pad_right("121", to: 3, with: ".")
+ /// "121"
+ ///
+ /// > pad_right("121", to: 2, with: ".")
+ /// "121"
+ ///
+ pub fn pad_right(string: String, to length: Int, with pad_string: String) {
+ erl_pad(string, length, Trailing, pad_string)
+ }
-external fn erl_trim(String, Direction) -> String =
- "string" "trim"
-
-/// Removes whitespace on both sides of a String.
-///
-/// ## Examples
-///
-/// > trim(" hats \n")
-/// "hats"
-///
-pub fn trim(string: String) -> String {
- erl_trim(string, Both)
-}
+ external fn erl_trim(String, Direction) -> String =
+ "string" "trim"
+
+ /// Removes whitespace on both sides of a String.
+ ///
+ /// ## Examples
+ ///
+ /// > trim(" hats \n")
+ /// "hats"
+ ///
+ pub fn trim(string: String) -> String {
+ erl_trim(string, Both)
+ }
-/// Removes whitespace on the left of a String.
-///
-/// ## Examples
-///
-/// > trim_left(" hats \n")
-/// "hats \n"
-///
-pub fn trim_left(string: String) -> String {
- erl_trim(string, Leading)
-}
+ /// Removes whitespace on the left of a String.
+ ///
+ /// ## Examples
+ ///
+ /// > trim_left(" hats \n")
+ /// "hats \n"
+ ///
+ pub fn trim_left(string: String) -> String {
+ erl_trim(string, Leading)
+ }
-/// Removes whitespace on the right of a String.
-///
-/// ## Examples
-///
-/// > trim_right(" hats \n")
-/// " hats"
-///
-pub fn trim_right(string: String) -> String {
- erl_trim(string, Trailing)
-}
+ /// Removes whitespace on the right of a String.
+ ///
+ /// ## Examples
+ ///
+ /// > trim_right(" hats \n")
+ /// " hats"
+ ///
+ pub fn trim_right(string: String) -> String {
+ erl_trim(string, Trailing)
+ }
-/// Splits a non-empty string into its head and tail. This lets you
-/// pattern match on strings exactly as you would with lists.
-///
-/// ## Examples
-/// > pop_grapheme("gleam")
-/// Ok(#("g", "leam"))
-///
-/// > pop_grapheme("")
-/// Error(Nil)
-///
-pub external fn pop_grapheme(string: String) -> Result(#(String, String), Nil) =
- "gleam_stdlib" "string_pop_grapheme"
-
-/// Converts a string to a list of Graphemes.
-///
-/// > to_graphemes("abc")
-/// ["a", "b", "c"]
-///
-pub fn to_graphemes(string: String) -> List(String) {
- case pop_grapheme(string) {
- Ok(#(grapheme, rest)) -> [grapheme, ..to_graphemes(rest)]
- _ -> []
+ /// Splits a non-empty string into its head and tail. This lets you
+ /// pattern match on strings exactly as you would with lists.
+ ///
+ /// ## Examples
+ /// > pop_grapheme("gleam")
+ /// Ok(#("g", "leam"))
+ ///
+ /// > pop_grapheme("")
+ /// Error(Nil)
+ ///
+ pub external fn pop_grapheme(string: String) -> Result(#(String, String), Nil) =
+ "gleam_stdlib" "string_pop_grapheme"
+
+ /// Converts a string to a list of Graphemes.
+ ///
+ /// > to_graphemes("abc")
+ /// ["a", "b", "c"]
+ ///
+ pub fn to_graphemes(string: String) -> List(String) {
+ case pop_grapheme(string) {
+ Ok(#(grapheme, rest)) -> [grapheme, ..to_graphemes(rest)]
+ _ -> []
+ }
}
-}
-external fn int_to_utf_codepoint(Int) -> UtfCodepoint =
- "gleam_stdlib" "identity"
-
-/// Converts an integer to a UtfCodepoint
-///
-/// Returns an error if the integer does not represent a valid UTF codepoint.
-///
-pub fn utf_codepoint(value: Int) -> Result(UtfCodepoint, Nil) {
- case value {
- i if i > 1114111 -> Error(Nil)
- 65534 | 65535 -> Error(Nil)
- i if i >= 55296 && i <= 57343 -> Error(Nil)
- i -> Ok(int_to_utf_codepoint(i))
+ external fn int_to_utf_codepoint(Int) -> UtfCodepoint =
+ "gleam_stdlib" "identity"
+
+ /// Converts an integer to a UtfCodepoint
+ ///
+ /// Returns an error if the integer does not represent a valid UTF codepoint.
+ ///
+ pub fn utf_codepoint(value: Int) -> Result(UtfCodepoint, Nil) {
+ case value {
+ i if i > 1114111 -> Error(Nil)
+ 65534 | 65535 -> Error(Nil)
+ i if i >= 55296 && i <= 57343 -> Error(Nil)
+ i -> Ok(int_to_utf_codepoint(i))
+ }
}
}
diff --git a/src/gleam/string_builder.gleam b/src/gleam/string_builder.gleam
index 36970b2..c09d60b 100644
--- a/src/gleam/string_builder.gleam
+++ b/src/gleam/string_builder.gleam
@@ -1,168 +1,170 @@
-/// StringBuilder is a type used for efficiently building strings.
-///
-/// When we append one string to another the strings must be copied to a
-/// new location in memory so that they can sit together. This behaviour
-/// enables efficient reading of the string but copying can be expensive,
-/// especially if we want to join many strings together.
-///
-/// StringBuilder is different in that it can be joined together in constant time
-/// using minimal memory, and then can be efficiently converted to a string
-/// using the `to_string` function.
-///
-pub external type StringBuilder
-
-/// Prepends a String onto the start of some StringBuilder.
-///
-/// Runs in constant time.
-///
-pub external fn prepend(to: StringBuilder, prefix: String) -> StringBuilder =
- "gleam_stdlib" "iodata_prepend"
-
-/// Appends a String onto the end of some StringBuilder.
-///
-/// Runs in constant time.
-///
-pub external fn append(to: StringBuilder, suffix: String) -> StringBuilder =
- "gleam_stdlib" "iodata_append"
-
-/// Prepends some StringBuilder onto the start of another.
-///
-/// Runs in constant time.
-///
-pub external fn prepend_builder(
- to: StringBuilder,
- prefix: StringBuilder,
-) -> StringBuilder =
- "gleam_stdlib" "iodata_prepend"
-
-/// Appends some StringBuilder onto the end of another.
-///
-/// Runs in constant time.
-///
-pub external fn append_builder(
- to: StringBuilder,
- suffix: StringBuilder,
-) -> StringBuilder =
- "gleam_stdlib" "iodata_append"
-
-/// Converts a list of strings into a builder.
-///
-/// Runs in constant time.
-///
-pub external fn from_strings(List(String)) -> StringBuilder =
- "gleam_stdlib" "identity"
-
-/// Joins a list of builders into a single builder.
-///
-/// Runs in constant time.
-///
-pub external fn concat(List(StringBuilder)) -> StringBuilder =
- "gleam_stdlib" "identity"
-
-/// Converts a string into a builder.
-///
-/// Runs in constant time.
-///
-pub external fn from_string(String) -> StringBuilder =
- "gleam_stdlib" "identity"
-
-/// Turns an `StringBuilder` into a `String`
-///
-/// This function is implemented natively by the virtual machine and is highly
-/// optimised.
-///
-pub external fn to_string(StringBuilder) -> String =
- "erlang" "iolist_to_binary"
-
-/// Returns the size of the StringBuilder in bytes.
-///
-pub external fn byte_size(StringBuilder) -> Int =
- "erlang" "iolist_size"
-
-/// Creates a builder containing the textual representation of a given float.
-///
-pub external fn from_float(Float) -> StringBuilder =
- "io_lib_format" "fwrite_g"
-
-/// Converts a builder to a new builder where the contents have been
-/// lowercased.
-///
-pub external fn lowercase(StringBuilder) -> StringBuilder =
- "string" "lowercase"
-
-/// Converts a builder to a new builder where the contents have been
-/// uppercased.
-///
-pub external fn uppercase(StringBuilder) -> StringBuilder =
- "string" "uppercase"
-
-/// Converts a builder to a new builder with the contents reversed.
-///
-pub external fn reverse(StringBuilder) -> StringBuilder =
- "string" "reverse"
-
-type Direction {
- All
+if erlang {
+ /// StringBuilder is a type used for efficiently building strings.
+ ///
+ /// When we append one string to another the strings must be copied to a
+ /// new location in memory so that they can sit together. This behaviour
+ /// enables efficient reading of the string but copying can be expensive,
+ /// especially if we want to join many strings together.
+ ///
+ /// StringBuilder is different in that it can be joined together in constant time
+ /// using minimal memory, and then can be efficiently converted to a string
+ /// using the `to_string` function.
+ ///
+ pub external type StringBuilder
+
+ /// Prepends a String onto the start of some StringBuilder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn prepend(to: StringBuilder, prefix: String) -> StringBuilder =
+ "gleam_stdlib" "iodata_prepend"
+
+ /// Appends a String onto the end of some StringBuilder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn append(to: StringBuilder, suffix: String) -> StringBuilder =
+ "gleam_stdlib" "iodata_append"
+
+ /// Prepends some StringBuilder onto the start of another.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn prepend_builder(
+ to: StringBuilder,
+ prefix: StringBuilder,
+ ) -> StringBuilder =
+ "gleam_stdlib" "iodata_prepend"
+
+ /// Appends some StringBuilder onto the end of another.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn append_builder(
+ to: StringBuilder,
+ suffix: StringBuilder,
+ ) -> StringBuilder =
+ "gleam_stdlib" "iodata_append"
+
+ /// Converts a list of strings into a builder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn from_strings(List(String)) -> StringBuilder =
+ "gleam_stdlib" "identity"
+
+ /// Joins a list of builders into a single builder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn concat(List(StringBuilder)) -> StringBuilder =
+ "gleam_stdlib" "identity"
+
+ /// Converts a string into a builder.
+ ///
+ /// Runs in constant time.
+ ///
+ pub external fn from_string(String) -> StringBuilder =
+ "gleam_stdlib" "identity"
+
+ /// Turns an `StringBuilder` into a `String`
+ ///
+ /// This function is implemented natively by the virtual machine and is highly
+ /// optimised.
+ ///
+ pub external fn to_string(StringBuilder) -> String =
+ "erlang" "iolist_to_binary"
+
+ /// Returns the size of the StringBuilder in bytes.
+ ///
+ pub external fn byte_size(StringBuilder) -> Int =
+ "erlang" "iolist_size"
+
+ /// Creates a builder containing the textual representation of a given float.
+ ///
+ pub external fn from_float(Float) -> StringBuilder =
+ "io_lib_format" "fwrite_g"
+
+ /// Converts a builder to a new builder where the contents have been
+ /// lowercased.
+ ///
+ pub external fn lowercase(StringBuilder) -> StringBuilder =
+ "string" "lowercase"
+
+ /// Converts a builder to a new builder where the contents have been
+ /// uppercased.
+ ///
+ pub external fn uppercase(StringBuilder) -> StringBuilder =
+ "string" "uppercase"
+
+ /// Converts a builder to a new builder with the contents reversed.
+ ///
+ pub external fn reverse(StringBuilder) -> StringBuilder =
+ "string" "reverse"
+
+ type Direction {
+ All
+ }
+
+ external fn erl_split(StringBuilder, String, Direction) -> List(StringBuilder) =
+ "string" "split"
+
+ /// Splits a builder on a given pattern into a list of builders.
+ ///
+ pub fn split(iodata: StringBuilder, on pattern: String) -> List(StringBuilder) {
+ erl_split(iodata, pattern, All)
+ }
+
+ external fn erl_replace(
+ StringBuilder,
+ String,
+ String,
+ Direction,
+ ) -> StringBuilder =
+ "string" "replace"
+
+ /// Replaces all instances of a pattern with a given string substitute.
+ ///
+ pub fn replace(
+ in iodata: StringBuilder,
+ each pattern: String,
+ with substitute: String,
+ ) -> StringBuilder {
+ erl_replace(iodata, pattern, substitute, All)
+ }
+
+ /// Compares two builders to determine if they have the same textual content.
+ ///
+ /// Comparing two iodata using the `==` operator may return False even if they
+ /// have the same content as they may have been build in different ways, so
+ /// using this function is often preferred.
+ ///
+ /// ## Examples
+ ///
+ /// > from_strings(["a", "b"]) == new("ab")
+ /// False
+ ///
+ /// > is_equal(from_strings(["a", "b"]), new("ab"))
+ /// True
+ ///
+ ///
+ pub external fn is_equal(StringBuilder, StringBuilder) -> Bool =
+ "string" "equal"
+
+ /// Inspects a builder to determine if it is equivalent to an empty string.
+ ///
+ /// ## Examples
+ ///
+ /// > new("ok") |> is_empty
+ /// False
+ ///
+ /// > new("") |> is_empty
+ /// True
+ ///
+ /// > from_strings([]) |> is_empty
+ /// True
+ ///
+ ///
+ pub external fn is_empty(StringBuilder) -> Bool =
+ "string" "is_empty"
}
-
-external fn erl_split(StringBuilder, String, Direction) -> List(StringBuilder) =
- "string" "split"
-
-/// Splits a builder on a given pattern into a list of builders.
-///
-pub fn split(iodata: StringBuilder, on pattern: String) -> List(StringBuilder) {
- erl_split(iodata, pattern, All)
-}
-
-external fn erl_replace(
- StringBuilder,
- String,
- String,
- Direction,
-) -> StringBuilder =
- "string" "replace"
-
-/// Replaces all instances of a pattern with a given string substitute.
-///
-pub fn replace(
- in iodata: StringBuilder,
- each pattern: String,
- with substitute: String,
-) -> StringBuilder {
- erl_replace(iodata, pattern, substitute, All)
-}
-
-/// Compares two builders to determine if they have the same textual content.
-///
-/// Comparing two iodata using the `==` operator may return False even if they
-/// have the same content as they may have been build in different ways, so
-/// using this function is often preferred.
-///
-/// ## Examples
-///
-/// > from_strings(["a", "b"]) == new("ab")
-/// False
-///
-/// > is_equal(from_strings(["a", "b"]), new("ab"))
-/// True
-///
-///
-pub external fn is_equal(StringBuilder, StringBuilder) -> Bool =
- "string" "equal"
-
-/// Inspects a builder to determine if it is equivalent to an empty string.
-///
-/// ## Examples
-///
-/// > new("ok") |> is_empty
-/// False
-///
-/// > new("") |> is_empty
-/// True
-///
-/// > from_strings([]) |> is_empty
-/// True
-///
-///
-pub external fn is_empty(StringBuilder) -> Bool =
- "string" "is_empty"
diff --git a/src/gleam/uri.gleam b/src/gleam/uri.gleam
index a65d753..b40b381 100644
--- a/src/gleam/uri.gleam
+++ b/src/gleam/uri.gleam
@@ -7,351 +7,353 @@
//// Query encoding (Form encoding) is defined in the w3c specification.
//// https://www.w3.org/TR/html52/sec-forms.html#urlencoded-form-data
-import gleam/list
-import gleam/result
-import gleam/option.{None, Option, Some}
-import gleam/string
-import gleam/dynamic.{Dynamic}
-import gleam/map.{Map}
-import gleam/function
-import gleam/pair
+if erlang {
+ import gleam/list
+ import gleam/result
+ import gleam/option.{None, Option, Some}
+ import gleam/string
+ import gleam/dynamic.{Dynamic}
+ import gleam/map.{Map}
+ import gleam/function
+ import gleam/pair
-/// Type representing holding the parsed components of an URI.
-/// All components of a URI are optional, except the path.
-///
-pub type Uri {
- Uri(
- scheme: Option(String),
- userinfo: Option(String),
- host: Option(String),
- port: Option(Int),
- path: String,
- query: Option(String),
- fragment: Option(String),
- )
-}
-
-pub external fn erl_parse(String) -> Dynamic =
- "uri_string" "parse"
+ /// Type representing holding the parsed components of an URI.
+ /// All components of a URI are optional, except the path.
+ ///
+ pub type Uri {
+ Uri(
+ scheme: Option(String),
+ userinfo: Option(String),
+ host: Option(String),
+ port: Option(Int),
+ path: String,
+ query: Option(String),
+ fragment: Option(String),
+ )
+ }
-type UriKey {
- Scheme
- Userinfo
- Host
- Port
- Path
- Query
- Fragment
-}
+ pub external fn erl_parse(String) -> Dynamic =
+ "uri_string" "parse"
-/// Parses a compliant URI string into the `Uri` Type.
-/// If the string is not a valid URI string then an error is returned.
-///
-/// The opposite operation is `uri.to_string`
-///
-/// ## Examples
-///
-/// ```
-/// > parse("https://example.com:1234/a/b?query=true#fragment")
-///
-/// Ok(Uri(scheme: Some("https"), ...))
-/// ```
-///
-pub fn parse(string: String) -> Result(Uri, Nil) {
- try uri_map =
- dynamic.map(erl_parse(string))
- |> result.nil_error
- let get = fn(k: UriKey, decode_type: dynamic.Decoder(t)) -> Option(t) {
- uri_map
- |> map.get(dynamic.from(k))
- |> result.then(function.compose(decode_type, result.nil_error))
- |> option.from_result
+ type UriKey {
+ Scheme
+ Userinfo
+ Host
+ Port
+ Path
+ Query
+ Fragment
}
- let uri =
- Uri(
- scheme: get(Scheme, dynamic.string),
- userinfo: get(Userinfo, dynamic.string),
- host: get(Host, dynamic.string),
- port: get(Port, dynamic.int),
- path: option.unwrap(get(Path, dynamic.string), ""),
- query: get(Query, dynamic.string),
- fragment: get(Fragment, dynamic.string),
- )
- Ok(uri)
-}
+ /// Parses a compliant URI string into the `Uri` Type.
+ /// If the string is not a valid URI string then an error is returned.
+ ///
+ /// The opposite operation is `uri.to_string`
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > parse("https://example.com:1234/a/b?query=true#fragment")
+ ///
+ /// Ok(Uri(scheme: Some("https"), ...))
+ /// ```
+ ///
+ pub fn parse(string: String) -> Result(Uri, Nil) {
+ try uri_map =
+ dynamic.map(erl_parse(string))
+ |> result.nil_error
+ let get = fn(k: UriKey, decode_type: dynamic.Decoder(t)) -> Option(t) {
+ uri_map
+ |> map.get(dynamic.from(k))
+ |> result.then(function.compose(decode_type, result.nil_error))
+ |> option.from_result
+ }
-external fn erl_parse_query(String) -> Dynamic =
- "uri_string" "dissect_query"
+ let uri =
+ Uri(
+ scheme: get(Scheme, dynamic.string),
+ userinfo: get(Userinfo, dynamic.string),
+ host: get(Host, dynamic.string),
+ port: get(Port, dynamic.int),
+ path: option.unwrap(get(Path, dynamic.string), ""),
+ query: get(Query, dynamic.string),
+ fragment: get(Fragment, dynamic.string),
+ )
+ Ok(uri)
+ }
-/// Parses an urlencoded query string into a list of key value pairs.
-/// Returns an error for invalid encoding.
-///
-/// The opposite operation is `uri.query_to_string`.
-///
-/// ## Examples
-///
-/// ```
-/// > parse_query("a=1&b=2")
-///
-/// Ok([#("a", "1"), #("b", "2")])
-/// ```
-///
-pub fn parse_query(query: String) -> Result(List(#(String, String)), Nil) {
- let bool_value = fn(x) { result.map(dynamic.bool(x), fn(_) { "" }) }
- let query_param = dynamic.typed_tuple2(
- _,
- dynamic.string,
- dynamic.any(_, of: [dynamic.string, bool_value]),
- )
+ external fn erl_parse_query(String) -> Dynamic =
+ "uri_string" "dissect_query"
- query
- |> erl_parse_query
- |> dynamic.typed_list(of: query_param)
- |> result.nil_error
-}
+ /// Parses an urlencoded query string into a list of key value pairs.
+ /// Returns an error for invalid encoding.
+ ///
+ /// The opposite operation is `uri.query_to_string`.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > parse_query("a=1&b=2")
+ ///
+ /// Ok([#("a", "1"), #("b", "2")])
+ /// ```
+ ///
+ pub fn parse_query(query: String) -> Result(List(#(String, String)), Nil) {
+ let bool_value = fn(x) { result.map(dynamic.bool(x), fn(_) { "" }) }
+ let query_param = dynamic.typed_tuple2(
+ _,
+ dynamic.string,
+ dynamic.any(_, of: [dynamic.string, bool_value]),
+ )
-type Encoding {
- Utf8
-}
+ query
+ |> erl_parse_query
+ |> dynamic.typed_list(of: query_param)
+ |> result.nil_error
+ }
-type ErlQueryToStringOption {
- Encoding(Encoding)
-}
+ type Encoding {
+ Utf8
+ }
-external fn erl_query_to_string(
- List(#(String, String)),
- List(ErlQueryToStringOption),
-) -> Dynamic =
- "uri_string" "compose_query"
+ type ErlQueryToStringOption {
+ Encoding(Encoding)
+ }
-/// Encodes a list of key value pairs as a URI query string.
-///
-/// The opposite operation is `uri.parse_query`.
-///
-/// ## Examples
-///
-/// ```
-/// > query_to_string([#("a", "1"), #("b", "2")])
-///
-/// "a=1&b=2"
-/// ```
-///
-pub fn query_to_string(query: List(#(String, String))) -> String {
- query
- |> erl_query_to_string([Encoding(Utf8)])
- |> dynamic.string
- |> result.unwrap("")
-}
+ external fn erl_query_to_string(
+ List(#(String, String)),
+ List(ErlQueryToStringOption),
+ ) -> Dynamic =
+ "uri_string" "compose_query"
-/// Encodes a string into a percent encoded representation.
-/// Note that this encodes space as +.
-///
-/// ## Examples
-///
-/// ```
-/// > percent_encode("100% great")
-///
-/// "100%25+great"
-/// ```
-///
-pub fn percent_encode(value: String) -> String {
- query_to_string([#("k", value)])
- |> string.replace(each: "k=", with: "")
-}
+ /// Encodes a list of key value pairs as a URI query string.
+ ///
+ /// The opposite operation is `uri.parse_query`.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > query_to_string([#("a", "1"), #("b", "2")])
+ ///
+ /// "a=1&b=2"
+ /// ```
+ ///
+ pub fn query_to_string(query: List(#(String, String))) -> String {
+ query
+ |> erl_query_to_string([Encoding(Utf8)])
+ |> dynamic.string
+ |> result.unwrap("")
+ }
-/// Decodes a percent encoded string.
-///
-/// ## Examples
-///
-/// ```
-/// > percent_decode("100%25+great")
-///
-/// Ok("100% great")
-/// ```
-///
-pub fn percent_decode(value: String) -> Result(String, Nil) {
- string.concat(["k=", value])
- |> parse_query
- |> result.then(list.head)
- |> result.map(pair.second)
-}
+ /// Encodes a string into a percent encoded representation.
+ /// Note that this encodes space as +.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > percent_encode("100% great")
+ ///
+ /// "100%25+great"
+ /// ```
+ ///
+ pub fn percent_encode(value: String) -> String {
+ query_to_string([#("k", value)])
+ |> string.replace(each: "k=", with: "")
+ }
+
+ /// Decodes a percent encoded string.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > percent_decode("100%25+great")
+ ///
+ /// Ok("100% great")
+ /// ```
+ ///
+ pub fn percent_decode(value: String) -> Result(String, Nil) {
+ string.concat(["k=", value])
+ |> parse_query
+ |> result.then(list.head)
+ |> result.map(pair.second)
+ }
-fn do_remove_dot_segments(
- input: List(String),
- accumulator: List(String),
-) -> List(String) {
- case input {
- [] -> list.reverse(accumulator)
- [segment, ..rest] -> {
- let accumulator = case segment, accumulator {
- "", accumulator -> accumulator
- ".", accumulator -> accumulator
- "..", [] -> []
- "..", [_, ..accumulator] -> accumulator
- segment, accumulator -> [segment, ..accumulator]
+ fn do_remove_dot_segments(
+ input: List(String),
+ accumulator: List(String),
+ ) -> List(String) {
+ case input {
+ [] -> list.reverse(accumulator)
+ [segment, ..rest] -> {
+ let accumulator = case segment, accumulator {
+ "", accumulator -> accumulator
+ ".", accumulator -> accumulator
+ "..", [] -> []
+ "..", [_, ..accumulator] -> accumulator
+ segment, accumulator -> [segment, ..accumulator]
+ }
+ do_remove_dot_segments(rest, accumulator)
}
- do_remove_dot_segments(rest, accumulator)
}
}
-}
-fn remove_dot_segments(input: List(String)) -> List(String) {
- do_remove_dot_segments(input, [])
-}
+ fn remove_dot_segments(input: List(String)) -> List(String) {
+ do_remove_dot_segments(input, [])
+ }
-/// Splits the path section of a URI into it's constituent segments.
-///
-/// Removes empty segments and resolves dot-segments as specified in
-/// [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC.
-///
-/// ## Examples
-///
-/// ```
-/// > path_segments("/users/1")
-///
-/// ["users" ,"1"]
-/// ```
-///
-pub fn path_segments(path: String) -> List(String) {
- remove_dot_segments(string.split(path, "/"))
-}
+ /// Splits the path section of a URI into it's constituent segments.
+ ///
+ /// Removes empty segments and resolves dot-segments as specified in
+ /// [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > path_segments("/users/1")
+ ///
+ /// ["users" ,"1"]
+ /// ```
+ ///
+ pub fn path_segments(path: String) -> List(String) {
+ remove_dot_segments(string.split(path, "/"))
+ }
-external fn erl_to_string(Map(UriKey, Dynamic)) -> Dynamic =
- "uri_string" "recompose"
+ external fn erl_to_string(Map(UriKey, Dynamic)) -> Dynamic =
+ "uri_string" "recompose"
-/// Encodes a `Uri` value as a URI string.
-///
-/// The opposite operation is `uri.parse`.
-///
-/// ## Examples
-///
-/// ```
-/// > let uri = Uri(Some("http"), None, Some("example.com"), ...)
-/// > to_string(uri)
-///
-/// "https://example.com"
-/// ```
-///
-pub fn to_string(uri: Uri) -> String {
- let field = fn(key: UriKey, value: Option(anything)) -> Result(
- #(UriKey, Dynamic),
- Nil,
- ) {
- case value {
- Some(v) -> Ok(#(key, dynamic.from(v)))
- None -> Error(Nil)
+ /// Encodes a `Uri` value as a URI string.
+ ///
+ /// The opposite operation is `uri.parse`.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > let uri = Uri(Some("http"), None, Some("example.com"), ...)
+ /// > to_string(uri)
+ ///
+ /// "https://example.com"
+ /// ```
+ ///
+ pub fn to_string(uri: Uri) -> String {
+ let field = fn(key: UriKey, value: Option(anything)) -> Result(
+ #(UriKey, Dynamic),
+ Nil,
+ ) {
+ case value {
+ Some(v) -> Ok(#(key, dynamic.from(v)))
+ None -> Error(Nil)
+ }
}
- }
- [
- field(Scheme, uri.scheme),
- field(Userinfo, uri.userinfo),
- field(Host, uri.host),
- field(Port, uri.port),
- field(Path, option.Some(uri.path)),
- field(Query, uri.query),
- field(Fragment, uri.fragment),
- ]
- |> list.filter_map(fn(x) { x })
- |> map.from_list
- |> erl_to_string
- |> dynamic.string
- |> result.unwrap("")
-}
+ [
+ field(Scheme, uri.scheme),
+ field(Userinfo, uri.userinfo),
+ field(Host, uri.host),
+ field(Port, uri.port),
+ field(Path, option.Some(uri.path)),
+ field(Query, uri.query),
+ field(Fragment, uri.fragment),
+ ]
+ |> list.filter_map(fn(x) { x })
+ |> map.from_list
+ |> erl_to_string
+ |> dynamic.string
+ |> result.unwrap("")
+ }
-/// Fetches the origin of a uri
-///
-/// Return the origin of a uri as defined in
-/// https://tools.ietf.org/html/rfc6454
-///
-/// The supported uri schemes are `http` and `https`
-/// Urls without a scheme will return Error
-///
-/// ## Examples
-///
-/// ```
-/// > assert Ok(uri) = parse("http://example.com/path?foo#bar")
-/// > origin(uri)
-///
-/// Ok("http://example.com")
-/// ```
-///
-pub fn origin(uri: Uri) -> Result(String, Nil) {
- let Uri(scheme: scheme, host: host, port: port, ..) = uri
- case scheme {
- Some("https") | Some("http") -> {
- let origin = Uri(scheme, None, host, port, "", None, None)
- Ok(to_string(origin))
+ /// Fetches the origin of a uri
+ ///
+ /// Return the origin of a uri as defined in
+ /// https://tools.ietf.org/html/rfc6454
+ ///
+ /// The supported uri schemes are `http` and `https`
+ /// Urls without a scheme will return Error
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// > assert Ok(uri) = parse("http://example.com/path?foo#bar")
+ /// > origin(uri)
+ ///
+ /// Ok("http://example.com")
+ /// ```
+ ///
+ pub fn origin(uri: Uri) -> Result(String, Nil) {
+ let Uri(scheme: scheme, host: host, port: port, ..) = uri
+ case scheme {
+ Some("https") | Some("http") -> {
+ let origin = Uri(scheme, None, host, port, "", None, None)
+ Ok(to_string(origin))
+ }
+ _ -> Error(Nil)
}
- _ -> Error(Nil)
}
-}
-fn drop_last(elements: List(a)) -> List(a) {
- list.take(from: elements, up_to: list.length(elements) - 1)
-}
+ fn drop_last(elements: List(a)) -> List(a) {
+ list.take(from: elements, up_to: list.length(elements) - 1)
+ }
-fn join_segments(segments: List(String)) -> String {
- string.join(["", ..segments], "/")
-}
+ fn join_segments(segments: List(String)) -> String {
+ string.join(["", ..segments], "/")
+ }
-/// Resolves a uri with respect to the given base uri
-///
-/// The base uri must be an absolute uri or this function will return an error.
-/// The algorithm for merging uris is described in [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2)
-pub fn merge(base: Uri, relative: Uri) -> Result(Uri, Nil) {
- case base {
- Uri(scheme: Some(_), host: Some(_), ..) ->
- case relative {
- Uri(host: Some(_), ..) -> {
- let path =
- string.split(relative.path, "/")
- |> remove_dot_segments()
- |> join_segments()
- let resolved =
- Uri(
- option.or(relative.scheme, base.scheme),
- None,
- relative.host,
- relative.port,
- path,
- relative.query,
- relative.fragment,
- )
- Ok(resolved)
- }
- Uri(scheme: None, host: None, ..) -> {
- let #(new_path, new_query) = case relative.path {
- "" -> #(base.path, option.or(relative.query, base.query))
- _ -> {
- let path_segments = case string.starts_with(relative.path, "/") {
- True -> string.split(relative.path, "/")
- False ->
- string.split(base.path, "/")
- |> drop_last()
- |> list.append(string.split(relative.path, "/"))
+ /// Resolves a uri with respect to the given base uri
+ ///
+ /// The base uri must be an absolute uri or this function will return an error.
+ /// The algorithm for merging uris is described in [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2)
+ pub fn merge(base: Uri, relative: Uri) -> Result(Uri, Nil) {
+ case base {
+ Uri(scheme: Some(_), host: Some(_), ..) ->
+ case relative {
+ Uri(host: Some(_), ..) -> {
+ let path =
+ string.split(relative.path, "/")
+ |> remove_dot_segments()
+ |> join_segments()
+ let resolved =
+ Uri(
+ option.or(relative.scheme, base.scheme),
+ None,
+ relative.host,
+ relative.port,
+ path,
+ relative.query,
+ relative.fragment,
+ )
+ Ok(resolved)
+ }
+ Uri(scheme: None, host: None, ..) -> {
+ let #(new_path, new_query) = case relative.path {
+ "" -> #(base.path, option.or(relative.query, base.query))
+ _ -> {
+ let path_segments = case string.starts_with(relative.path, "/") {
+ True -> string.split(relative.path, "/")
+ False ->
+ string.split(base.path, "/")
+ |> drop_last()
+ |> list.append(string.split(relative.path, "/"))
+ }
+ let path =
+ path_segments
+ |> remove_dot_segments()
+ |> join_segments()
+ #(path, relative.query)
}
- let path =
- path_segments
- |> remove_dot_segments()
- |> join_segments()
- #(path, relative.query)
}
+ let resolved =
+ Uri(
+ base.scheme,
+ None,
+ base.host,
+ base.port,
+ new_path,
+ new_query,
+ relative.fragment,
+ )
+ Ok(resolved)
}
- let resolved =
- Uri(
- base.scheme,
- None,
- base.host,
- base.port,
- new_path,
- new_query,
- relative.fragment,
- )
- Ok(resolved)
}
- }
- _ -> Error(Nil)
+ _ -> Error(Nil)
+ }
}
}
diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl
index 10d3752..fe70eea 100644
--- a/src/gleam_stdlib.erl
+++ b/src/gleam_stdlib.erl
@@ -14,10 +14,18 @@
decode_bit_string/1, compile_regex/2, regex_match/2, regex_split/2,
regex_scan/2, base_decode64/1, wrap_list/1, rescue/1, get_line/1]).
-should_equal(Actual, Expected) -> ?assertEqual(Expected, Actual).
-should_not_equal(Actual, Expected) -> ?assertNotEqual(Expected, Actual).
-should_be_ok(A) -> ?assertMatch({ok, _}, A).
-should_be_error(A) -> ?assertMatch({error, _}, A).
+should_equal(Actual, Expected) ->
+ ?assertEqual(Expected, Actual),
+ nil.
+should_not_equal(Actual, Expected) ->
+ ?assertNotEqual(Expected, Actual),
+ nil.
+should_be_ok(A) ->
+ ?assertMatch({ok, _}, A),
+ nil.
+should_be_error(A) ->
+ ?assertMatch({error, _}, A),
+ nil.
map_get(Map, Key) ->
case maps:find(Key, Map) of
diff --git a/src/gleam_stdlib.js b/src/gleam_stdlib.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/gleam_stdlib.js