std.record
apply_on : forall a b. String -> (a -> a -> b) -> { _ : a } -> { _ : a } -> b
apply_on field f a b
is equivalent to f a."${field}" b."${field}"
Useful for comparisons.
Examples
std.record.apply_on "name" std.string.compare { name = "Alice", age = 27 } { name = "Bob", age = 23 }
# => 'Lesser
std.record.apply_on "age" std.number.compare { name = "Alice", age = 27 } { name = "Bob", age = 23 }
# => 'Greater
fields : forall a. { _ : a } -> Array String
Returns an array containing the names of all the fields of a record.
Empty optional fields
By default, fields
ignores optional fields without definition. An
empty optional field won't be listed in the result.
Use std.record.fields_with_opts
for a version which doesn't ignore
empty optional fields.
Examples
std.record.fields { one = 1, two = 2 }
# => [ "one", "two" ]
std.record.fields { one = 1, two = 2, three_opt | optional }
# => [ "one", "two" ]
fields_with_opts : forall a. { _ : a } -> Array String
Returns an array containing the names of all the fields of a record.
Same as std.record.fields
, but doesn't ignore empty optional fields.
Examples
std.record.fields_with_opts { one = 1, two = 2 }
# => [ "one", "two" ]
std.record.fields_with_opts { one = 1, two = 2, three_opt | optional }
# => [ "one", "two", "three_opt" ]
filter : forall a. (String -> a -> Bool) -> { _ : a } -> { _ : a }
filter f r
returns a record containing all fields from r
for which
f
returns true. The function f
is passed the name and value of each field
to make a decision.
Examples
std.record.filter (fun _name x => x % 2 == 0) { even = 2, odd = 3 }
# => { even = 2 }
from_array : forall a. Array { field : String, value : a } -> { _ : a }
Converts an array of key-value pairs into a record. The field names in the input array must be distinct.
Examples
std.record.from_array [
{ field = "hello", value = "world" },
{ field = "foo", value = "bar" }
]
# => { hello = "world", foo = "bar" }
get : forall a. String -> { _ : a } -> a
get | std.contract.unstable.HasField Dyn
Returns the field of a record with the given name.
std.record.get field record
is just record."%{field}"
. The latter
form is more idiomatic and should be generally preferred.
However, std.record.get
can come in handy when a proper function is
expected, typically in a sequence of operations chained with the reverse
application operator |>
.
Trying to extract a field which doesn't exist will result in a contract error.
Examples
std.record.get "one" { one = 1, two = 2 }
# => 1
{ one = 1, two = 2, string = "three"}
|> std.record.to_array
|> std.array.filter (fun { field, value } => std.is_number value)
|> std.record.from_array
|> std.record.get "two"
# => 2
get_or : forall a. String -> a -> { _ : a } -> a
Returns the field of a record with the given name, or the default value if either there is no such field or if this field doesn't have a definition.
Examples
std.record.get_or "tree" 3 { one = 1, two = 2 }
# => 3
std.record.get_or "one" 11 { one = 1, two = 2 }
# => 1
std.record.get_or "value" "default" { tag = 'Hello, value }
# => "default"
has_field : forall a. String -> { _ : a } -> Bool
Given a string, checks if a record contains a field of that name.
Empty optional fields
By default, has_field
ignores optional fields without definition.
Use std.record.has_field_with_opts
for a version which doesn't ignore
empty optional fields.
Examples
std.record.has_field "hello" { one = 1, two = 2 }
# => false
std.record.has_field "one" { one = 1, two = 2 }
# => true
std.record.has_field "two_opt" { one, two_opt | optional }
# => false
({ one = 1 } | {one, two_opt | optional })
|> std.record.has_field "two_opt"
# => false
has_field_with_opts : forall a. String -> { _ : a } -> Bool
Given a string, checks if a record contains a field of that name.
Same as std.record.has_field
, but doesn't ignore empty optional
fields.
Examples
std.record.has_field_with_opts "hello" { one = 1, two = 2 }
# => false
std.record.has_field_with_opts "one" { one = 1, two = 2 }
# => true
std.record.has_field_with_opts "two_opt" { one, two_opt | optional }
# => true
({ one = 1 } | {one, two_opt | optional })
|> std.record.has_field_with_opts "two_opt"
# => true
insert : forall a. String -> a -> { _ : a } -> { _ : a }
Inserts a new field into a record. insert
doesn't mutate the original
record but returns a new one instead.
Preconditions
The field must not exist in the initial record, otherwise insert
will fail. If the field might already exist, use std.record.update
instead.
Empty optional fields
By default, insert
ignores optional fields without definition. The
precondition above doesn't apply to empty optional fields, and
insert
will silently erase an existing empty optional field.
Use std.record.insert_with_opts
for a version which doesn't ignore
empty optional fields.
Examples
std.record.insert "foo" 5 { bar = "bar" }
# => { foo = 5, bar = "bar" }
{}
|> std.record.insert "file.txt" "data/text"
|> std.record.insert "length" (10*1000)
# => {"file.txt" = "data/text", "length" = 10000}
std.record.insert "already_there_opt" 0 {already_there_opt | optional}
# => {already_there_opt = 0}
std.record.insert "already_there" 0 {already_there = 1}
# => error
insert_with_opts : forall a. String -> a -> { _ : a } -> { _ : a }
Inserts a new field into a record. insert_with_opts
doesn't mutate the
original record but returns a new one instead.
Same as std.record.insert
, but doesn't ignore empty optional fields.
Preconditions
The field must not exist in the initial record, otherwise insert
will fail. If the field might already exist, use std.record.update
instead.
Examples
std.record.insert_with_opts "foo" 5 { bar = "bar" }
# => { foo = 5, bar = "bar" }
{}
|> std.record.insert_with_opts "file.txt" "data/text"
|> std.record.insert_with_opts "length" (10*1000)
# => {"file.txt" = "data/text", "length" = 10000}
std.record.insert_with_opts "already_there_optional" 0 {already_there | optional}
# => { already_there_optional = 0 }
std.record.insert_with_opts "already_there" 0 {already_there = 1}
# => error
is_empty : forall a. { _ : a } -> Bool
Checks whether a record is empty.
Examples
std.record.is_empty {}
# => true
std.record.is_empty { foo = 1 }
# => false
length : forall a. { _ : a } -> Number
Returns the number of fields in a record. This count doesn't include fields both marked as optional and without a definition.
Because of the need to filter empty optional fields, the cost of
length
is linear in the size of the record.
map : forall a b. (String -> a -> b) -> { _ : a } -> { _ : b }
Maps a function over every field of a record. The function is passed the name and value of each field.
Examples
std.record.map (fun s x => s) { hi = 2 }
# => { hi = "hi" }
std.record.map (fun s x => x + 1) { hello = 1, world = 2 }
# => { hello = 2, world = 3 }
map_values : forall a b. (a -> b) -> { _ : a } -> { _ : b }
Maps a function over the values of all the fields of a record.
map_values f
is the same as std.record.map (fun _field => f)
.
Examples
std.record.map_values (fun x => x + 1) { hi = 2 }
# => { hi = 3 }
std.record.map_values (fun x => x + 1) { hello = 1, world = 2 }
# => { hello = 2, world = 3 }
merge_all : Array ({ _ : Dyn }) -> { _ : Dyn }
Merges an array of records.
Examples
std.record.merge_all [ { foo = 1 }, { bar = 2 } ]
# => { foo = 1, bar = 2 }
remove : forall a. String -> { _ : a } -> { _ : a }
Removes a field from a record. remove
doesn't mutate the original
record but returns a new one instead.
Preconditions
The field to remove must be present in the record, or remove
will
fail.
Empty optional fields
By default, remove
ignores optional fields. The precondition above
doesn't apply to an empty optional field and remove
will fail with a
missing field error when trying to remove an empty optional field.
Use std.record.remove_with_opts
for a version which doesn't ignore
empty optional fields.
Examples
std.record.remove "foo" { foo = "foo", bar = "bar" }
# => { bar = "bar" }
std.record.remove "foo_opt" {foo_opt | optional}
# => error
std.record.remove "foo" { bar = "bar" }
# => error
remove_with_opts : forall a. String -> { _ : a } -> { _ : a }
Removes a field from a record. remove
doesn't mutate the original
record but returns a new one instead.
Same as std.record.remove
, but doesn't ignore empty optional fields.
Preconditions
The field to remove must be present in the record, or remove
will
fail.
Examples
std.record.remove_with_opts "foo" { foo = "foo", bar = "bar" }
# => { bar = "bar" }
std.record.remove_with_opts "foo_opt" {foo_opt | optional}
# => {}
std.record.remove_with_opts "foo" { bar = "bar" }
# => error
to_array : forall a. { _ : a } -> Array { field : String, value : a }
Converts a record to an array of key-value pairs.
Examples
std.record.to_array { hello = "world", foo = "bar" }
# => [ { field = "hello", value = "world" }, { field = "foo", value = "bar" } ]
update : forall a. String -> a -> { _ : a } -> { _ : a }
Updates a field of a record with a new value. update
doesn't mutate the
original record but returns a new one instead. If the field to update is absent
from the given record, update
adds it.
Empty optional fields
update
works the same way for empty optional fields and other fields.
update
guarantees that it can always replace a field with a new
value, no matter the nature of the field.
Examples
std.record.update "foo" 5 { foo = "foo", bar = "bar" }
# => { foo = 5, bar = "bar" }
std.record.update "foo" 5 { bar = "bar" }
# => { foo = 5, bar = "bar" }
std.record.update "foo_opt" 5 {foo_opt | optional}
# => {foo_opt = 5}
Overriding
As opposed to overriding a value with the merge operator &
, update
will only change the specified field and won't automatically update the other
fields which depend on it:
{ foo = bar + 1, bar | default = 0 } & { bar = 1 }
# => { foo = 2, bar = 1 }
std.record.update "bar" 1 {foo = bar + 1, bar | default = 0 }
# => { foo = 1, bar = 1 }
values : forall a. { _ : a } -> Array a
Returns an array containing the values of all the fields of a record.
Examples
std.record.values { one = 1, world = "world" }
# => [ 1, "world" ]