aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2020-04-28 19:10:36 +0100
committerLouis Pilfold <louis@lpil.uk>2020-04-28 19:10:36 +0100
commitf31235eb6b36bbab51651e3ea8733437c7e34600 (patch)
tree4336e62f6256406fa2b72189e63ba2899c8d4fe7
parent3482f3071696598422fa02be98228e95f6d0376a (diff)
downloadgleam_stdlib-f31235eb6b36bbab51651e3ea8733437c7e34600.tar.gz
gleam_stdlib-f31235eb6b36bbab51651e3ea8733437c7e34600.zip
Docs ready for v0.8
-rw-r--r--CHANGELOG.md6
-rw-r--r--gen/test/gleam@dynamic_test.erl16
-rw-r--r--src/gleam/atom.gleam1
-rw-r--r--src/gleam/bool.gleam25
-rw-r--r--src/gleam/dynamic.gleam65
-rw-r--r--src/gleam/float.gleam38
-rw-r--r--src/gleam/function.gleam2
-rw-r--r--src/gleam/int.gleam44
-rw-r--r--src/gleam/order.gleam39
-rw-r--r--src/gleam/pair.gleam10
-rw-r--r--src/gleam/result.gleam114
-rw-r--r--src/gleam/string.gleam308
-rw-r--r--src/gleam_stdlib.erl27
-rw-r--r--test/gleam/dynamic_test.gleam16
14 files changed, 434 insertions, 277 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 70c51ab..a3e9ce0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,12 @@
- The `string` module gains `is_empty`, `join` and `concat` functions.
- The `int` module gains `is_even` and `is_odd` functions.
- The `list.length` function now accepts a labelled argument.
+- The `list.length` function now accepts a labelled argument.
+- The the second argument of `bool.compare`, `float.compare`, `int.compare`,
+ and `order.compare` now have the label `with`.
+- The `dynamic.unsafe_coerce` function now only accepts Dynamic data.
+- The `dynamic` decoder functions no longer print the entire value in their
+ error messages, to avoid large errors.
## v0.7.0 - 2020-03-03
diff --git a/gen/test/gleam@dynamic_test.erl b/gen/test/gleam@dynamic_test.erl
index 587b168..785af15 100644
--- a/gen/test/gleam@dynamic_test.erl
+++ b/gen/test/gleam@dynamic_test.erl
@@ -14,11 +14,11 @@ string_test() ->
),
gleam@should:equal(
gleam@dynamic:string(gleam@dynamic:from(1)),
- {error, <<"Expected a String, got `1`"/utf8>>}
+ {error, <<"Expected a string, got an int"/utf8>>}
),
gleam@should:equal(
gleam@dynamic:string(gleam@dynamic:from([])),
- {error, <<"Expected a String, got `[]`"/utf8>>}
+ {error, <<"Expected a string, got a list"/utf8>>}
).
int_test() ->
@@ -26,11 +26,11 @@ int_test() ->
gleam@should:equal(gleam@dynamic:int(gleam@dynamic:from(2)), {ok, 2}),
gleam@should:equal(
gleam@dynamic:int(gleam@dynamic:from(1.0)),
- {error, <<"Expected an Int, got `1.0`"/utf8>>}
+ {error, <<"Expected an int, got a float"/utf8>>}
),
gleam@should:equal(
gleam@dynamic:int(gleam@dynamic:from([])),
- {error, <<"Expected an Int, got `[]`"/utf8>>}
+ {error, <<"Expected an int, got a list"/utf8>>}
).
float_test() ->
@@ -38,11 +38,11 @@ float_test() ->
gleam@should:equal(gleam@dynamic:float(gleam@dynamic:from(2.2)), {ok, 2.2}),
gleam@should:equal(
gleam@dynamic:float(gleam@dynamic:from(1)),
- {error, <<"Expected a Float, got `1`"/utf8>>}
+ {error, <<"Expected a float, got an int"/utf8>>}
),
gleam@should:equal(
gleam@dynamic:float(gleam@dynamic:from([])),
- {error, <<"Expected a Float, got `[]`"/utf8>>}
+ {error, <<"Expected a float, got a list"/utf8>>}
).
thunk_test() ->
@@ -71,11 +71,11 @@ bool_test() ->
),
gleam@should:equal(
gleam@dynamic:bool(gleam@dynamic:from(1)),
- {error, <<"Expected a Bool, got `1`"/utf8>>}
+ {error, <<"Expected a bool, got an int"/utf8>>}
),
gleam@should:equal(
gleam@dynamic:bool(gleam@dynamic:from([])),
- {error, <<"Expected a Bool, got `[]`"/utf8>>}
+ {error, <<"Expected a bool, got a list"/utf8>>}
).
atom_test() ->
diff --git a/src/gleam/atom.gleam b/src/gleam/atom.gleam
index a806fc8..8e9cb04 100644
--- a/src/gleam/atom.gleam
+++ b/src/gleam/atom.gleam
@@ -34,7 +34,6 @@ pub type FromStringError {
/// > from_string("some_new_atom")
/// Error(AtomNotLoaded)
///
-///
pub external fn from_string(String) -> Result(Atom, FromStringError) =
"gleam_stdlib" "atom_from_string";
diff --git a/src/gleam/bool.gleam b/src/gleam/bool.gleam
index 8a01235..4a9cebf 100644
--- a/src/gleam/bool.gleam
+++ b/src/gleam/bool.gleam
@@ -11,12 +11,17 @@ import gleam/order.{Order}
pub type Bool =
Bool
-/// Returns the opposite Bool value
+/// 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 {
@@ -28,12 +33,12 @@ pub fn negate(bool: Bool) -> Bool {
/// Compares two bools and returns the first values Order to the second.
///
/// ## Examples
-/// import gleam/order
+///
+/// > import gleam/order
/// > compare(True, False)
/// order.Gt
///
-///
-pub fn compare(a: Bool, b: Bool) -> Order {
+pub fn compare(a: Bool, with b: Bool) -> Order {
case a, b {
True, True -> order.Eq
True, False -> order.Gt
@@ -42,9 +47,10 @@ pub fn compare(a: Bool, b: Bool) -> Order {
}
}
-/// Returns `True` if either Bool value is `True`.
+/// Returns True if either bool value is True.
///
/// ## Examples
+///
/// > max(True, False)
/// True
///
@@ -54,7 +60,6 @@ pub fn compare(a: Bool, b: Bool) -> Order {
/// > max(False, False)
/// False
///
-///
pub fn max(a: Bool, b: Bool) -> Bool {
case a {
True -> True
@@ -62,9 +67,10 @@ pub fn max(a: Bool, b: Bool) -> Bool {
}
}
-/// Returns `False` if either Bool value is `False`.
+/// Returns False if either bool value is False.
///
/// ## Examples
+///
/// > max(True, False)
/// False
///
@@ -74,7 +80,6 @@ pub fn max(a: Bool, b: Bool) -> Bool {
/// > max(False, False)
/// False
///
-///
pub fn min(a: Bool, b: Bool) -> Bool {
case a {
False -> False
@@ -82,16 +87,16 @@ pub fn min(a: Bool, b: Bool) -> Bool {
}
}
-/// Returns a numeric representation of the value:
+/// 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
diff --git a/src/gleam/dynamic.gleam b/src/gleam/dynamic.gleam
index 488ad45..4355e59 100644
--- a/src/gleam/dynamic.gleam
+++ b/src/gleam/dynamic.gleam
@@ -14,13 +14,17 @@ pub external fn from(a) -> Dynamic = "gleam_stdlib" "identity";
/// Unsafely cast 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.
+/// native Erlang APIs. It is to be used as a last measure only!
///
-pub external fn unsafe_coerce(a) -> b = "gleam_stdlib" "identity";
+/// If you can avoid using this function, do!
+///
+pub external fn unsafe_coerce(Dynamic) -> a = "gleam_stdlib" "identity";
-/// Safely cast a Dynamic value into a String.
+/// Check to see whether a Dynamic value is a string, and return the string if
+/// it is.
///
/// ## Examples
+///
/// > string(from("Hello"))
/// Ok("Hello")
///
@@ -30,9 +34,11 @@ pub external fn unsafe_coerce(a) -> b = "gleam_stdlib" "identity";
pub external fn string(from: Dynamic) -> Result(String, String)
= "gleam_stdlib" "decode_string"
-/// Safely cast a Dynamic value into a String.
+/// Check to see whether a Dynamic value is an int, and return the int if it
+/// is.
///
/// ## Examples
+///
/// > int(from(123))
/// Ok(123)
///
@@ -42,9 +48,11 @@ pub external fn string(from: Dynamic) -> Result(String, String)
pub external fn int(from: Dynamic) -> Result(Int, String)
= "gleam_stdlib" "decode_int"
-/// Safely cast a Dynamic value into a Float.
+/// Check to see whether a Dynamic value is an float, and return the float if
+/// it is.
///
/// ## Examples
+///
/// > float(from(2.0))
/// Ok(2.0)
///
@@ -54,10 +62,12 @@ pub external fn int(from: Dynamic) -> Result(Int, String)
pub external fn float(from: Dynamic) -> Result(Float, String)
= "gleam_stdlib" "decode_float"
-/// Safely cast a Dynamic value into an Atom.
+/// Check to see whether a Dynamic value is an atom, and return the atom if
+/// it is.
///
/// ## Examples
-/// import gleam/atom
+///
+/// > import gleam/atom
/// > atom(from(atom.create_from_string("hello")))
/// OK("hello")
///
@@ -67,9 +77,11 @@ pub external fn float(from: Dynamic) -> Result(Float, String)
pub external fn atom(from: Dynamic) -> Result(atom.Atom, String)
= "gleam_stdlib" "decode_atom"
-/// Safely cast a Dynamic value into a Bool.
+/// Check to see whether a Dynamic value is an bool, and return the bool if
+/// it is.
///
/// ## Examples
+///
/// > bool(from(True))
/// Ok(True)
///
@@ -79,11 +91,13 @@ pub external fn atom(from: Dynamic) -> Result(atom.Atom, String)
pub external fn bool(from: Dynamic) -> Result(Bool, String)
= "gleam_stdlib" "decode_bool"
-/// Safely cast a Dynamic value into a String.
+/// Check 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 }
+///
+/// > import gleam/result
+/// > let f = fn() { 1 }
/// > thunk(from(f)) |> result.is_ok
/// True
///
@@ -96,14 +110,19 @@ pub external fn thunk(from: Dynamic) -> Result(fn() -> Dynamic, String)
external fn list_dynamic(from: Dynamic) -> Result(List(Dynamic), String)
= "gleam_stdlib" "decode_list"
-/// Safely cast a Dynamic value into a List of some type.
+/// Check to see whether a Dynamic value is a list, and return the list if it
+/// is.
///
/// ## Examples
+///
/// > list(from(["a", "b", "c"]), string)
/// Ok(["a", "b", "c"])
///
/// > list(from([1, 2, 3]), string)
-/// Error("Expected a List, got `[1, 2, 3]`")
+/// Error("Expected an Int, got a binary")
+///
+/// > list(from("ok"), string)
+/// Error("Expected a List, got a binary")
///
pub fn list(
from dynamic: Dynamic,
@@ -114,28 +133,36 @@ pub fn list(
|> result.then(_, list_mod.traverse(_, decoder_type))
}
-/// Returns a field from a Dynamic value representing a map if it exists.
+/// Check 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
+///
+/// > import gleam/map
/// > field(from(map.new("Hello", "World")), "Hello")
/// Ok(Dynamic)
///
-/// > field(from(123))
-/// Error("Expected a map with key `\"Hello\"`, got `123`")
+/// > 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"
-/// Returns an element of a Dynamic value representing a tuple if it exists.
+/// Check 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(tuple(1, 2)), 0)
/// Ok(Dynamic)
///
/// > element(from(tuple(1, 2)), 2)
-/// Error("Element position is out-of-bounds")
+/// 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"
diff --git a/src/gleam/float.gleam b/src/gleam/float.gleam
index 499c7fc..918ecc2 100644
--- a/src/gleam/float.gleam
+++ b/src/gleam/float.gleam
@@ -5,7 +5,8 @@ import gleam/result.{Option}
pub type Float =
Float
-/// Attempts to parse the String as a Float if possible
+/// Attempts to parse a string as a float, returning `Error(Nil)` if it was not
+/// possible.
///
/// ## Examples
/// > parse("2.3")
@@ -14,33 +15,28 @@ pub type Float =
/// > parse("ABC")
/// None
///
-///
pub external fn parse(String) -> Option(Float)
= "gleam_stdlib" "parse_float";
-/// Returns the string representation of the provided
-/// `Float` value
+/// Return the string representation of the provided float.
///
/// ## Examples
/// > to_string(2.3)
/// "2.3"
///
-///
pub fn to_string(f: Float) -> String {
f
|> iodata.from_float
|> iodata.to_string
}
-
-/// Compares two `Floats`, returning an `Order`
+/// Compares two floats, returning an order.
///
/// ## Examples
/// > compare(2.0, 2.3)
/// Lt
///
-///
-pub fn compare(a: Float, b: Float) -> Order {
+pub fn compare(a: Float, with b: Float) -> Order {
case a == b {
True -> order.Eq
False ->
@@ -51,13 +47,13 @@ pub fn compare(a: Float, b: Float) -> Order {
}
}
-/// Compares two `Floats`, returning the smaller of the two
+/// 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
@@ -65,13 +61,13 @@ pub fn min(a: Float, b: Float) -> Float {
}
}
-/// Compares two `Floats`, returning the larger of the two
+/// 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
@@ -79,41 +75,41 @@ pub fn max(a: Float, b: Float) -> Float {
}
}
-/// Rounds the value to the next highest whole number as a Float
+/// 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
+/// 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
+/// 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.
+/// Returns the value as an int, truncating all decimal digits.
///
/// ## Examples
+///
/// > truncate(2.4343434847383438)
/// 2
///
-///
pub external fn truncate(Float) -> Int = "erlang" "trunc";
diff --git a/src/gleam/function.gleam b/src/gleam/function.gleam
index c0d699d..b92c0ac 100644
--- a/src/gleam/function.gleam
+++ b/src/gleam/function.gleam
@@ -2,7 +2,7 @@
/// 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) { fun1(a) |> fun2 }
+ fn(a) { fun2(fun1(a)) }
}
/// Takes a function that takes two arguments and returns a new function that
diff --git a/src/gleam/int.gleam b/src/gleam/int.gleam
index 95992fd..a0a0462 100644
--- a/src/gleam/int.gleam
+++ b/src/gleam/int.gleam
@@ -4,32 +4,31 @@ import gleam/result.{Option}
pub type Int =
Int
-/// Attempts to parse the String as an Int if possible
+/// Parse a given string as an int if possible.
///
/// ## Examples
+///
/// > parse("2")
-/// Some(2)
+/// Ok(2)
///
/// > parse("ABC")
-/// None
-///
+/// Error(Nil)
///
pub external fn parse(String) -> Option(Int) = "gleam_stdlib" "parse_int";
-/// Returns the string representation of the provided
-/// `Int` value
+/// Print a given int to a string.
///
/// ## Examples
+///
/// > to_string(2)
/// "2"
///
-///
pub external fn to_string(Int) -> String = "erlang" "integer_to_binary"
-/// Returns the string representation of the provided
-/// `Int` value in the base provided.
+/// Print a given int to a string using the base number provided.
///
/// ## Examples
+///
/// > to_base_string(2, 2)
/// "10"
///
@@ -39,17 +38,22 @@ pub external fn to_string(Int) -> String = "erlang" "integer_to_binary"
/// > to_base_string(48, 36)
/// "1C"
///
-///
pub external fn to_base_string(Int, Int) -> String = "erlang" "integer_to_binary"
-/// Compares two `Int`, returning an `Order`
+/// Compares two ints, returning an order.
///
/// ## Examples
+///
/// > compare(2, 3)
/// Lt
///
+/// > compare(4, 3)
+/// Gt
+///
+/// > compare(3, 3)
+/// Eq
///
-pub fn compare(a: Int, b: Int) -> Order {
+pub fn compare(a: Int, with b: Int) -> Order {
case a == b {
True -> order.Eq
False ->
@@ -60,13 +64,13 @@ pub fn compare(a: Int, b: Int) -> Order {
}
}
-/// Compares two `Int`, returning the smaller of the two
+/// 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
@@ -74,13 +78,13 @@ pub fn min(a: Int, b: Int) -> Int {
}
}
-/// Compares two `Int`, returning the larger of the two
+/// 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
@@ -88,30 +92,30 @@ pub fn max(a: Int, b: Int) -> Int {
}
}
-/// Returns whether the value provided is even
+/// 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
+/// 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
}
diff --git a/src/gleam/order.gleam b/src/gleam/order.gleam
index 5c4df19..c030db4 100644
--- a/src/gleam/order.gleam
+++ b/src/gleam/order.gleam
@@ -1,17 +1,30 @@
/// Represents the result of a single comparison to determine the precise
/// ordering of two values.
+///
pub type Order {
+ /// Less-than
Lt
+
+ /// Equal
Eq
+
+ /// Greater than
Gt
}
-/// Switches the evaluated ordering from one direction to the other
+/// 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 {
@@ -21,12 +34,18 @@ pub fn reverse(order: Order) -> Order {
}
}
-/// Produces a numeric representation of the order
+/// 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 {
@@ -36,14 +55,14 @@ pub fn to_int(order: Order) -> Int {
}
}
-/// Compares two Order values to one another, producing a new Order
+/// Compares two Order values to one another, producing a new Order.
///
/// ## Examples
-/// > compare(Eq, to: Lt)
-/// Gt
///
+/// > compare(Eq, with: Lt)
+/// Gt
///
-pub fn compare(a: Order, to b: Order) -> Order {
+pub fn compare(a: Order, with b: Order) -> Order {
case a, b {
x, y if x == y -> Eq
Lt, _ | Eq, Gt -> Lt
@@ -51,13 +70,13 @@ pub fn compare(a: Order, to b: Order) -> Order {
}
}
-/// Returns the highest of two orders
+/// Returns the largest of two orders.
///
/// ## Examples
+///
/// > max(Eq, Lt)
/// Eq
///
-///
pub fn max(a: Order, b: Order) -> Order {
case a, b {
Gt, _ -> Gt
@@ -66,13 +85,13 @@ pub fn max(a: Order, b: Order) -> Order {
}
}
-/// Returns the lowest of two orders
+/// Returns the smallest of two orders.
///
/// ## Examples
+///
/// > min(Eq, Lt)
/// Lt
///
-///
pub fn min(a: Order, b: Order) -> Order {
case a, b {
Lt, _ -> Lt
diff --git a/src/gleam/pair.gleam b/src/gleam/pair.gleam
index 4a2e592..f0de5a9 100644
--- a/src/gleam/pair.gleam
+++ b/src/gleam/pair.gleam
@@ -1,10 +1,10 @@
/// Returns the first element in a pair.
///
/// ## Examples
+///
/// > first(tuple(1, 2))
/// 1
///
-///
pub fn first(pair: tuple(a, b)) -> a {
let tuple(a, _) = pair
a
@@ -13,10 +13,10 @@ pub fn first(pair: tuple(a, b)) -> a {
/// Returns the second element in a pair.
///
/// ## Examples
+///
/// > second(tuple(1, 2))
/// 2
///
-///
pub fn second(pair: tuple(a, b)) -> b {
let tuple(_, a) = pair
a
@@ -25,10 +25,10 @@ pub fn second(pair: tuple(a, b)) -> b {
/// Returns a new pair with the elements swapped.
///
/// ## Examples
+///
/// > swap(tuple(1, 2))
/// tuple(2, 1)
///
-///
pub fn swap(pair: tuple(a, b)) -> tuple(b, a) {
let tuple(a, b) = pair
tuple(b, a)
@@ -38,10 +38,10 @@ pub fn swap(pair: tuple(a, b)) -> tuple(b, a) {
/// it.
///
/// ## Examples
+///
/// > tuple(1, 2) |> map_first(fn(n) { n * 2 })
/// 2
///
-///
pub fn map_first(of pair: tuple(a, b), with fun: fn(a) -> c) -> tuple(c, b) {
let tuple(a, b) = pair
tuple(fun(a), b)
@@ -51,10 +51,10 @@ pub fn map_first(of pair: tuple(a, b), with fun: fn(a) -> c) -> tuple(c, b) {
/// it.
///
/// ## Examples
+///
/// > tuple(1, 2) |> map_second(fn(n) { n * 2 })
/// 4
///
-///
pub fn map_second(of pair: tuple(a, b), with fun: fn(b) -> c) -> tuple(a, c) {
let tuple(a, b) = pair
tuple(a, fun(b))
diff --git a/src/gleam/result.gleam b/src/gleam/result.gleam
index 69dfb8b..b002f8e 100644
--- a/src/gleam/result.gleam
+++ b/src/gleam/result.gleam
@@ -1,5 +1,6 @@
-/// Result represents the result of something that may succeed or fail.
-/// `Ok` means it was successful, `Error` means it failed.
+/// 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)
@@ -9,14 +10,28 @@ pub type Result(success, error) =
/// Unlike some other languages values cannot be implicitly nil, value that may
/// be absent is typically represented using `Result(TheType, Nil)`. This is
/// such a common type that offer the `Option(TheType)` alias.
+///
pub type Nil =
Nil
/// A value that is either there or not there.
+///
+/// Some other languages have a dedicated Option type that is not related to
+/// Result for this, however this tends to have all the same functions as
+/// Result so in Gleam we combine the two.
+///
pub type Option(value) =
Result(value, Nil)
-/// Returns whether the value is Ok
+/// Check 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 {
@@ -25,7 +40,16 @@ pub fn is_ok(result: Result(a, e)) -> Bool {
}
}
-/// Returns whether the value is Error
+/// Check 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
@@ -33,8 +57,19 @@ pub fn is_error(result: Result(a, e)) -> Bool {
}
}
-/// Executes the function `with` on inner value when Result is Ok, will noop
-/// if it is Error
+/// Update 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),
@@ -46,8 +81,19 @@ pub fn map(
}
}
-/// Will execute the function `with` on inner value when Result is Err, will noop
-/// if it is Ok
+/// Update 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),
@@ -59,7 +105,18 @@ pub fn map_error(
}
}
-/// Will unnest the inner value of a result nested within another result
+/// Merge 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 {
@@ -68,9 +125,29 @@ pub fn flatten(result: Result(Result(a, e), e)) -> Result(a, e) {
}
}
-/// Executes the function `apply` on inner value when Result is Ok, will noop
-/// if it is Error
-/// Equivalent to `map` followed by `flatten`.
+/// Update 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(tuple("a", x)) })
+/// Ok(tuple("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),
@@ -82,8 +159,16 @@ pub fn then(
}
}
-/// Will return the inner value of a Ok value. If an error, will
-/// return the value provided as `or`
+/// Extract 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 {
@@ -99,7 +184,6 @@ pub fn unwrap(result: Result(a, e), or default: a) -> a {
/// > none()
/// Error(Nil)
///
-///
pub fn none() -> Option(a) {
Error(Nil)
}
diff --git a/src/gleam/string.gleam b/src/gleam/string.gleam
index 2b59f60..de6f58a 100644
--- a/src/gleam/string.gleam
+++ b/src/gleam/string.gleam
@@ -1,6 +1,7 @@
-/// A built-in representation for efficient string manipulation. String literals
-/// are enclosed in `"double quotes"`.
-///
+//// Strings in Gleam are UTF-8 binaries. They can be written in your code a
+//// text surrounded by `"double quotes"`.
+////
+
import gleam/iodata
import gleam/list
import gleam/order
@@ -9,38 +10,48 @@ import gleam/result.{Option}
pub type String =
String
-/// ## Basics
-
/// Determine if a string is empty.
///
/// ## Examples
+///
/// > is_empty("")
/// True
///
/// > is_empty("the world")
/// False
///
-///
pub fn is_empty(str: String) -> Bool {
str == ""
}
-/// Get the length of a
+/// Get 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"
/// Reverse 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
|> iodata.new
@@ -48,16 +59,16 @@ pub fn reverse(string: String) -> String {
|> iodata.to_string
}
-/// Replace all occurrences of some substring.
+/// Create a new string by replacing all occurrences of a given substring.
///
/// ## Examples
-/// > replace("Json.Decode.succeed", each: ".", with: "-")
-/// "Json-Decode-succeed"
+///
+/// > 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,
@@ -69,55 +80,60 @@ pub fn replace(
|> iodata.to_string
}
-/// Convert a string to all lower case. Useful for case-insensitive comparisons.
+/// Create 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"
-/// Convert a string to all upper case. Useful for case-insensitive comparisons
-/// and VIRTUAL YELLING.
+/// Create 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"
-/// Determines the order of the two strings.
+/// 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.Gt
///
-///
pub external fn compare(String, String) -> order.Order =
"gleam_stdlib" "compare_strings"
-/// ## Get Substrings
-
// TODO
-/// Take a substring given a start and end Grapheme indexes. Negative indexes
-/// are taken starting from the *end* of the list.
-///
-/// ## Examples
-/// > slice("gleam", from: 1, to: 3)
-/// "lea"
-///
-/// > slice("gleam", from: 1, to: 10)
-/// "leam"
-///
-/// > slice("snakes on a plane!", from: -6, to: -1)
-/// "plane"
-///
-///
+// Take a substring given a start and end Grapheme indexes. Negative indexes
+// are taken starting from the *end* of the list.
+//
+// ## Examples
+// > slice("gleam", from: 1, to: 3)
+// "lea"
+//
+// > slice("gleam", from: 1, to: 10)
+// "leam"
+//
+// > slice("snakes on a plane!", from: -6, to: -1)
+// "plane"
+//
+//
// pub fn slice(out_of string: String, from start: Int, end: Int) -> String {}
// TODO
@@ -131,20 +147,20 @@ pub external fn compare(String, String) -> order.Order =
// pub fn drop_left(from string: String, up_to num_graphemes: Int) -> String {}
// TODO
-/// Drop *n* Graphemes from the right side of a
-///
-/// ## Examples
-/// > drop_right(from: "Cigarette Smoking Man", up_to: 2)
-/// "Cigarette Smoking M"
-///
-///
+// Drop *n* Graphemes from the right side of a
+//
+// ## 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 {}
-/// ## Check for Substrings
/// Check if the first string contains the second.
///
/// ## Examples
+///
/// > contains(does: "theory", contain: "ory")
/// True
///
@@ -154,7 +170,6 @@ pub external fn compare(String, String) -> order.Order =
/// > contains(does: "theory", contain: "THE")
/// False
///
-///
external fn erl_contains(String, String) -> Bool =
"gleam_stdlib" "string_contains"
@@ -164,34 +179,32 @@ pub fn contains(does haystack: String, contain needle: String) -> Bool {
// TODO
// TODO: Not sure about the name and labels here
-/// See if the second string starts with the first one.
-///
-/// ## Examples
-/// > starts_with(does: "theory", start_with: "ory")
-/// False
-///
-///
+// See if the second string starts with the first one.
+//
+// ## Examples
+// > starts_with(does: "theory", start_with: "ory")
+// False
+//
+//
// pub fn starts_with(does string: String, start_with prefix: String) -> String {}
// TODO
// TODO: Not sure about the name and labels here
-/// See if the second string ends with the first one.
-///
-/// ## Examples
-/// > ends_with(does: "theory", end_with: "ory")
-/// True
-///
-///
+// See if the second string ends with the first one.
+//
+// ## Examples
+// > ends_with(does: "theory", end_with: "ory")
+// True
+//
+//
// pub fn ends_with(does string: String, end_with suffix: String) -> String {}
-/// ## Building and Splitting
-
-/// Split a string using a given separator.
+/// Create a list of strings by splitting a given string on a given substring.
///
/// ## Examples
-/// > split("home/evan/Desktop/", on: "/")
-/// ["home","evan","Desktop", ""]
///
+/// > split("home/gleam/desktop/", on: "/")
+/// ["home","gleam","desktop", ""]
///
pub fn split(x: String, on substring: String) -> List(String) {
x
@@ -201,13 +214,17 @@ pub fn split(x: String, on substring: String) -> List(String) {
}
-/// Append two strings.
+/// Create 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 [iodata](../iodata)
+/// 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
|> iodata.new
@@ -215,26 +232,23 @@ pub fn append(to first: String, suffix second: String) -> String {
|> iodata.to_string
}
-/// Concatenate many strings into one.
+/// Create 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 [iodata](../iodata)
+/// module as it can append strings much faster!
///
/// ## Examples
+///
/// > concat(["never", "the", "less"])
/// "nevertheless"
///
-///
pub fn concat(strings: List(String)) -> String {
strings
|> iodata.from_strings
|> iodata.to_string
}
-/// Repeat a string `n` times.
-///
-/// ## Examples
-/// > repeat("ha", times: 3)
-/// "hahaha"
-///
-///
fn repeat_help(chunk: String, result: List(String), repeats: Int) -> String {
case repeats <= 0 {
True -> concat(result)
@@ -242,17 +256,27 @@ fn repeat_help(chunk: String, result: List(String), repeats: Int) -> String {
}
}
+/// Create 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 {
repeat_help(string, [], times)
}
/// Join 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)
@@ -260,102 +284,84 @@ pub fn join(strings: List(String), with separator: String) -> String {
|> iodata.to_string
}
-/// ## Formatting
-
// TODO
-/// Pad 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"
-///
-///
+// Pad 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 size: Int, with: String) {}
// TODO
-/// Pad 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"
-///
-///
+// Pad 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 size: Int, with: String) {}
// TODO
-/// Get rid of whitespace on both sides of a String.
-///
-/// ## Examples
-/// > trim(" hats \n")
-/// "hats"
-///
-///
+// Get rid of whitespace on both sides of a String.
+//
+// ## Examples
+// > trim(" hats \n")
+// "hats"
+//
+//
// pub fn trim(string: String) -> String {}
// TODO
-/// Get rid of whitespace on the left of a String.
-///
-/// ## Examples
-/// > trim_left(" hats \n")
-/// "hats \n"
-///
-///
+// Get rid of whitespace on the left of a String.
+//
+// ## Examples
+// > trim_left(" hats \n")
+// "hats \n"
+//
+//
// pub fn trim_left(string: String) -> String {}
// TODO
-/// Get rid of whitespace on the right of a String.
-///
-/// ## Examples
-/// > trim_right(" hats \n")
-/// " hats"
-///
-///
+// Get rid of whitespace on the right of a String.
+//
+// ## Examples
+// > trim_right(" hats \n")
+// " hats"
+//
+//
// pub fn trim_right(string: String) -> String {}
-/// ## Grapheme Conversions
-
-// These functions convert to and from Grapheme, which currently
-// does not exist as a type in Gleam.
-
// TODO
// /// Convert a string to a list of Graphemes.
// ///
// /// > to_graphemes("abc")
-/// ['a','b','c']
-///
+// ['a','b','c']
+//
// ///
// pub fn to_graphemes(string: String) -> List(String) {}
// TODO
-// /// Convert a list of characters into a String. Can be useful if you
-// /// want to create a string primarily by consing, perhaps for decoding
-// /// something.
-// ///
-// /// > from_list(['a','b','c'])
-/// "abc"
-///
-// ///
-// // pub fn from_graphemes(graphemes: List(Grapheme)) -> String {}
-
-// TODO
-/// Split a non-empty string into its head and tail. This lets you
-/// pattern match on strings exactly as you would with lists.
-///
-/// ## Examples
-/// > next_grapheme("")
-/// Error(Nil)
-///
-///
+// Split a non-empty string into its head and tail. This lets you
+// pattern match on strings exactly as you would with lists.
+//
+// ## Examples
+// > next_grapheme("")
+// Error(Nil)
+//
+//
// pub fn next_grapheme(string: String) -> Option(tuple(Grapheme, String)) {}
diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl
index 9e6a864..49a7e2a 100644
--- a/src/gleam_stdlib.erl
+++ b/src/gleam_stdlib.erl
@@ -39,28 +39,37 @@ iodata_prepend(Iodata, String) -> [String, Iodata].
identity(X) -> X.
decode_error_msg(Type, Data) ->
- {error, iolist_to_binary(io_lib:format("Expected ~s, got `~p`", [Type, Data]))}.
+ {error, iolist_to_binary(io_lib:format("Expected ~s, got ~s", [Type, classify(Data)]))}.
+
+classify(X) when is_atom(X) -> "an atom";
+classify(X) when is_binary(X) -> "a binary";
+classify(X) when is_integer(X) -> "an int";
+classify(X) when is_float(X) -> "a float";
+classify(X) when is_list(X) -> "a list";
+classify(X) when is_boolean(X) -> "a bool";
+classify(X) when is_function(X, 0) -> "a zero arity function";
+classify(_) -> "some other type".
decode_atom(Data) when is_atom(Data) -> {ok, Data};
-decode_atom(Data) -> decode_error_msg("an Atom", Data).
+decode_atom(Data) -> decode_error_msg("an atom", Data).
decode_string(Data) when is_binary(Data) -> {ok, Data};
-decode_string(Data) -> decode_error_msg("a String", Data).
+decode_string(Data) -> decode_error_msg("a string", Data).
decode_int(Data) when is_integer(Data) -> {ok, Data};
-decode_int(Data) -> decode_error_msg("an Int", Data).
+decode_int(Data) -> decode_error_msg("an int", Data).
decode_float(Data) when is_float(Data) -> {ok, Data};
-decode_float(Data) -> decode_error_msg("a Float", Data).
+decode_float(Data) -> decode_error_msg("a float", Data).
decode_bool(Data) when is_boolean(Data) -> {ok, Data};
-decode_bool(Data) -> decode_error_msg("a Bool", Data).
+decode_bool(Data) -> decode_error_msg("a bool", Data).
decode_thunk(Data) when is_function(Data, 0) -> {ok, Data};
decode_thunk(Data) -> decode_error_msg("a zero arity function", Data).
decode_list(Data) when is_list(Data) -> {ok, Data};
-decode_list(Data) -> decode_error_msg("a List", Data).
+decode_list(Data) -> decode_error_msg("a list", Data).
decode_field(Data, Key) ->
case Data of
@@ -74,7 +83,9 @@ decode_field(Data, Key) ->
decode_element(Data, Position) when is_tuple(Data) ->
case catch element(Position + 1, Data) of
{'EXIT', _Reason} ->
- {error, "Element position is out-of-bounds"};
+ Reason = io_lib:format("Expected a tuple of at least ~w size, got a tuple of ~w sise",
+ [Position + 1, tuple_size(Data)]),
+ {error, Reason};
Value ->
{ok, Value}
diff --git a/test/gleam/dynamic_test.gleam b/test/gleam/dynamic_test.gleam
index 080e6e7..2a777c7 100644
--- a/test/gleam/dynamic_test.gleam
+++ b/test/gleam/dynamic_test.gleam
@@ -19,12 +19,12 @@ pub fn string_test() {
1
|> dynamic.from
|> dynamic.string
- |> should.equal(_, Error("Expected a String, got `1`"))
+ |> should.equal(_, Error("Expected a string, got an int"))
[]
|> dynamic.from
|> dynamic.string
- |> should.equal(_, Error("Expected a String, got `[]`"))
+ |> should.equal(_, Error("Expected a string, got a list"))
}
pub fn int_test() {
@@ -41,12 +41,12 @@ pub fn int_test() {
1.0
|> dynamic.from
|> dynamic.int
- |> should.equal(_, Error("Expected an Int, got `1.0`"))
+ |> should.equal(_, Error("Expected an int, got a float"))
[]
|> dynamic.from
|> dynamic.int
- |> should.equal(_, Error("Expected an Int, got `[]`"))
+ |> should.equal(_, Error("Expected an int, got a list"))
}
pub fn float_test() {
@@ -63,12 +63,12 @@ pub fn float_test() {
1
|> dynamic.from
|> dynamic.float
- |> should.equal(_, Error("Expected a Float, got `1`"))
+ |> should.equal(_, Error("Expected a float, got an int"))
[]
|> dynamic.from
|> dynamic.float
- |> should.equal(_, Error("Expected a Float, got `[]`"))
+ |> should.equal(_, Error("Expected a float, got a list"))
}
pub fn thunk_test() {
@@ -113,12 +113,12 @@ pub fn bool_test() {
1
|> dynamic.from
|> dynamic.bool
- |> should.equal(_, Error("Expected a Bool, got `1`"))
+ |> should.equal(_, Error("Expected a bool, got an int"))
[]
|> dynamic.from
|> dynamic.bool
- |> should.equal(_, Error("Expected a Bool, got `[]`"))
+ |> should.equal(_, Error("Expected a bool, got a list"))
}
pub fn atom_test() {