module std.tf
The std
module contains libraries for general computing tasks.
library core
The core library contains utility functions to process values at a basic level.
id
(any x) -> any
Identity function. Returns x
.
> core.id("foo")
"foo"
> core.id({:a "b"})
{
:a "b"
}
> core.id(nil)
nil
inspect
(x) -> string
Returns a string representation of x
.
If x
is a function the string 'function'
is returned.
Otherwise literal notation is used.
If x
is not a function, and contains no functions as children x == core.eval(core.inspect(x))
generally holds true.
> core.inspect(1)
"1"
> core.inspect([1, 2, 3])
"[1, 2, 3]"
> core.inspect(nil)
"nil"
> core.inspect({:a 1, :b 2})
"{
:a 1,
:b 2
}"
> core.inspect("foo")
"\"foo\""
present?
(x) -> boolean
Returns false
if x
is nil
, returns true
otherwise.
> core.present?("foo")
true
> core.present?(nil)
false
nil?
(x) -> boolean
Returns true
if x
is nil
, returns false
otherwise.
> core.nil?("foo")
false
> core.nil?(nil)
true
hash
(x) -> long
Returns a hashcode of x
. Values that compare as equal are guaranteed to have the same hashcode.
> core.hash("foo")
101574
> core.hash(nil)
0
> core.hash([1,2,3])
66614367
> core.hash([1.0, 2.0, 3.0])
66614367
eval
(string x) -> any
Evaluates tweakflow source code x
in empty scope.
If x
represents a valid value, the value it is returned.
If x
cannot be evaluated, an error is thrown.
x
is evaluated in empty scope, so any references within x
must be self-contained.
Functions can be declared and called within x
.
Returns nil
if x
is nil
.
> core.eval("1")
1
> core.eval("'str'")
"str"
> core.eval(nil)
nil
> core.eval("(x) -> x+1")(1)
2
> core.eval("let {f: (x) -> x*x;} f(5)")
25
> core.eval("hello")
ERROR:
code: UNRESOLVED_REFERENCE
message: hello is undefined
at: <eval>:1:1
source: hello
library strings
The strings library contains basic functions for text processing.
concat
(list xs) -> string
Returns a string consisting of all xs
concatenated into a single string.
Each x
in xs
is cast to a string before concatenation.
If any x
cannot be cast to a string, an error is thrown.
If any x
is nil
, it is concatenated into the output string as "nil"
.
Returns nil
if xs
is nil
.
> strings.concat(["foo", "bar"])
"foobar"
> strings.concat([1, 2, 3])
"123"
> strings.concat(["a", nil, "b"])
"anilb"
> strings.concat([])
""
> strings.concat(nil)
nil
length
(string x) -> long
Returns the number of unicode codepoints in given string x
.
Returns nil
if x
is nil
.
> strings.length("")
0
> strings.length("foo")
3
> strings.length("你好")
2
substring
(string x, long start=0, long end=nil) -> string
Returns a substring of x
beginning at index start
(inclusive) up to index end
(exclusive).
If end
is nil
, the substring extends to the end of x
.
Returns an empty string if end <= start
.
Returns nil
if x
is nil
.
Throws an error if start
is nil
or start < 0
.
> strings.substring("hello world")
"hello world"
> strings.substring("hello world", 6)
"world"
> strings.substring("hello world", 6, 6)
""
> strings.substring("hello world", 6, 7)
"w"
> strings.substring("hello world", 6, 11)
"world"
> strings.substring("hello world", 6, -2)
""
> strings.substring(nil, 6)
nil
> strings.substring("你好", 0, 1)
"你"
> strings.substring("你好", 1, 2)
"好"
> strings.substring("hello world", nil)
ERROR:
code: NIL_ERROR
message: start must not be nil
> strings.substring("hello world", -4)
ERROR:
code: INDEX_OUT_OF_BOUNDS
message: start must not be negative: -4
replace
(string x, string search, string replace) -> string
Returns a string where each occurrence of search
in x
is replaced with replace
.
The replacement happens from left to right,
so strings.replace('ooo', 'oo', 'g')
results in 'go'
rather than 'og'
.
Returns nil
if any argument is nil
.
> strings.replace('ooo', 'oo', 'g')
"go"
> strings.replace('foo', 'oo', 'ast')
"fast"
> strings.replace('hello', 'e', 'u')
"hullo"
> strings.replace('grab', 'gr', '')
"ab"
> strings.replace('hello world', 'not found', 'something')
"hello world"
join
(list xs, string s="") -> string
Concatenates a list of xs
into a single string using s
as the separator.
Each x
in xs
is cast to a string before concatenation.
If any x
cannot be cast to a string, an error is thrown.
If any x
is nil
, it is concatenated into the output string as "nil"
.
Returns nil
if xs
is nil
or s
is nil
.
> strings.join(["foo", "bar"])
"foobar"
> strings.join(["foo", "bar"], ", ")
"foo, bar"
> strings.join([1, 2, 3], "-")
"1-2-3"
> strings.join([1, nil, 3], "-")
"1-nil-3"
> strings.join([])
""
> strings.join(nil, ", ")
nil
> strings.join(["a", "b"], nil)
nil
trim
(string x) -> string
Returns x
with leading and trailing whitespace characters removed.
Returns nil
if x
is nil
.
> strings.trim(" foo ")
"foo"
> strings.trim("line\r\n")
"line"
> strings.trim(nil)
nil
lower_case
(string x, string lang='en-US') -> string
Returns x
with all characters converted to lower case as per conventions of the given language tag.
Returns nil
if x
is nil
or lang
is nil
.
> strings.lower_case("FOO")
"foo"
> strings.lower_case("TITLE")
"title"
> strings.lower_case("TITLE", "tr")
"tıtle" # note the dotless i in turkish language
upper_case
(string x, string lang='en-US') -> string
Returns x
with all characters converted to uper case as per conventions of the given language tag.
Returns nil
if x
is nil
or lang
is nil
.
> strings.upper_case("foo")
"FOO"
> strings.upper_case("straße")
"STRASSE" # note that some characters may expand to multiple characters
> strings.upper_case("title", "tr")
"TİTLE" # note the dotted upper case I in turkish language
compare
(string a, string b) -> long
Compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings.
Returns -1 if a < b.
Returns 1 if a > b.
Returns 0 if a == b.\
This function considers nil
less than any non-nil string.
> data.sort(["Aaron", "Eve", "Adam", "Joe", "Beth", "Linda"], strings.compare)
["Aaron", "Adam", "Beth", "Eve", "Joe", "Linda"]
comparator
(
string lang='en-US',
boolean case_sensitive=true
) -> function
Returns a function f (string a, string b) -> long
that compares two strings a
and b
according to conventions appropriate for the given language tag.
If case_sensitive
is true
, lower case characters precede their upper case counterparts.
If case_sensitive
is false
, lower case characters are considered equal to their upper case conterparts.
f
returns -1 if a < b.
f
returns 1 if a > b.
f
returns 0 if a == b.\
f
considers nil
less than any non-nil string.
Throws an error if any argument is nil
.
> f: strings.comparator("en-US", true)
function
> f("foo", "FOO")
-1
> f: strings.comparator("en-US", false)
function
> f("foo", "FOO")
0
> data.sort(["Foo", "Bar", "foo", "bar", nil], strings.comparator("en-US", true))
[nil, "bar", "Bar", "foo", "Foo"]
> data.sort(["Foo", "Bar", "foo", "bar", nil], strings.comparator("en-US", false))
[nil, "Bar", "bar", "Foo", "foo"]
chars
(string x) -> list
Returns a list of characters that make up given string x
.
Returns nil
if x
is nil
.
> strings.chars("foo")
["f", "o", "o"]
> strings.chars("你好")
["你", "好"]
> strings.chars("")
[]
> strings.chars(nil)
nil
code_points
(string x) -> list
Returns a list of unicode code point numbers that make up given string x
.
Returns nil
if x
is nil
.
> strings.code_points("foo")
[102, 111, 111]
> strings.code_points("你好")
[20320, 22909]
> strings.code_points("")
[]
> strings.code_points(nil)
nil
of_code_points
(list xs) -> string
Returns string consisting of given xs
. The xs
are are longs representing unicode code point numbers.
Any non-long code point numbers in xs
are cast to long.
Returns nil
if xs
is nil
.
Throws an error if any of the xs
cannot be cast to long, or the value does not represent a
valid code point.
> strings.of_code_points([102, 111, 111])
"foo"
> strings.of_code_points([0x4F60, 0x597D, 0x01D11E])
"你好𝄞"
> strings.of_code_points([])
""
> strings.of_code_points(nil)
nil
split
(string x, string s=" ") -> list
Returns a list of strings obtained by splitting x
using separator s
.
The separator s
is treated like a regular string, it is not a regular expression.
Returns nil
if x
is nil
or s
is nil
.
> strings.split("hello world")
["hello", "world"]
> strings.split("a,b,c", ",")
["a", "b", "c"]
> strings.split("foo", ",")
["foo"]
> strings.split(",foo,,bar,", ",")
["", "foo", "", "bar", ""]
starts_with?
(string x, string init) -> boolean
Returns true
if x
starts with the substring init
.
Returns false
otherwise.
Returns true
for any non-nil x
if init
is the empty string.
Returns nil
if x
is nil
or init
is nil
.
> strings.starts_with?("yellow", "yell")
true
> strings.starts_with?("yellow", "blue")
false
> strings.starts_with?("yellow", "")
true
> strings.starts_with?(nil, "blue")
nil
> strings.starts_with?("yellow", nil)
nil
ends_with?
(string x, string tail) -> boolean
Returns true
if x
ends with the substring tail
.
Returns false
otherwise.
Returns true
for any non-nil x
if tail
is the empty string.
Returns nil
if x
is nil
or tail
is nil
.
> strings.ends_with?("yellow", "low")
true
> strings.ends_with?("yellow", "high")
false
> strings.ends_with?("yellow", "")
true
> strings.ends_with?(nil, "blue")
nil
> strings.ends_with?("yellow", nil)
nil
index_of
(string x, string sub, long start=0) -> long
If x
contains sub
at or past index start
, the function returns the index of the first occurrence of sub
at or past index start
.
Returns -1
otherwise.
Returns nil
if any argument is nil
.
> strings.index_of("foobar", "foo")
0
> strings.index_of("foobar", "bar")
3
> strings.index_of("foobar", "hello")
-1
> strings.index_of("foobar", "bar", 3)
3
> strings.index_of("foobar", "bar", 4)
-1
last_index_of
(string x, string sub, long end=nil) -> long
If x
contains sub
at or before index end
returns the index of the last such occurrence. Returns -1
otherwise.
If end
is nil
, it is interpreted as the last index of x
.
Returns nil
if x
is nil
or sub
is nil
.
> strings.last_index_of("elementary", "e")
4
> strings.last_index_of("elementary", "e", 100)
4
> strings.last_index_of("elementary", "e", 3)
2
> strings.last_index_of("elementary", "e", 1)
0
> strings.last_index_of("elementary", "e", -5)
-1
> strings.last_index_of("elementary", nil)
nil
> strings.last_index_of(nil, "e")
nil
char_at
(string x, long i) -> string
Returns i
th character in string x
.
Returns nil
if x
is nil
, i
is nil
, or i
is out of bounds: i<0
, i>=length(x)
.
> strings.char_at("elementary", 0)
"e"
> strings.char_at("你好", 1)
"好"
> strings.char_at(nil, 0)
nil
code_point_at
(string x, long i) -> long
Returns i
th character code point in string x
.
Returns nil
if x
is nil
, i
is nil
, or i
is out of bounds: i<0
, i>=length(x)
.
> strings.code_point_at("abc", 0)
97 # "a"
> strings.code_point_at("你好", 0)
20320 # "你"
> strings.code_point_at(nil, 0)
nil
to_bytes
(string x, string charset="UTF-8") -> binary
Returns binary representing the bytes of string x
using given charset
.
Returns nil
if x
is nil
or charset
is nil
.
> strings.to_bytes("abc")
0b616263
> strings.to_bytes("你好")
0bE4BDA0E5A5BD
> strings.to_bytes("bäcker")
0b62C3A4636B6572
> strings.to_bytes("bäcker", "ISO-8859-1")
0b62E4636B6572
> strings.to_bytes(nil)
nil
from_bytes
(binary x, string charset="UTF-8") -> string
Returns string represented by the bytes of x
using given charset
.
Returns nil
if x
is nil
or charset
is nil
.
> strings.from_bytes(0b616263)
"abc"
> strings.from_bytes(0bE4BDA0E5A5BD)
"你好"
> strings.from_bytes(0b62C3A4636B6572)
"bäcker"
> strings.from_bytes(0b62E4636B6572, "ISO-8859-1")
"bäcker"
> strings.from_bytes(nil)
nil
charsets
() -> list
Returns known charsets. Each item in the returned list is a charset name suitable for passing to functions requiring a charset name, such as to_bytes and from_bytes.
library regex
The regex library provides functions to work with regular expressions. Pattern syntax is that of the Java regular expression language.
matching
(string pattern) -> function
Returns a predicate function f
accepting one string argument x
that checks if the argument matches the given pattern
completely.
Calling f
with a nil
argument returns nil
.
Throws an error if pattern
is nil
or not a valid regular expression.
> digits?: regex.matching('\d+')
function
> digits?("12345")
true
> digits?("hello")
false
> digits?(nil)
nil
capturing
(string pattern) -> function
Returns a function f
accepting one string argument x
and returning a list of captured groups in the pattern.
In case pattern
matches the argument entirely, index 0
contains the input string, and subsequent indexes contain the matched groups. Group indexes correspond to the sequence of opening group parentheses of capturing groups in the pattern.
If a group is optional, and is not matched by the input string, its value in the list is nil
.
If a capturing group is inside a quantifier, only the last matched string is captured.
In case pattern
does not match the argument entirely, f
returns an empty list.
Calling f
with a nil
argument returns nil
.
Throws an error if pattern
is nil
or not a valid regular expression.
# match ISO date and optional hh:mm time, capturing year, month, day, time
> date_parts: regex.capturing('(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}:\d{2}))?')
function
> date_parts("2017-05-24")
["2017-05-24", "2017", "05", "24", nil]
> date_parts("2017-05-24T08:45")
["2017-05-24T08:45", "2017", "05", "24", "08:45"]
> date_parts("hello")
[]
> date_parts(nil)
nil
scanning
(string pattern) -> function
Returns a function f
accepting one string argument x
and returning a list of captured groups for each successive match of the pattern in x
.
Each match generates a list with the following properties: Index 0
contains the matched input string, and subsequent indexes contain the matched groups. Group indexes correspond to the sequence of opening group parentheses of capturing groups in the pattern.
If a group is optional, and is not matched by the input string, its value in the list is nil
.
In case pattern
does not match x
, f
returns an empty list.
Calling f
with a nil
argument returns nil
.
Throws an error if pattern
is nil
or not a valid regular expression.
# scan for hh:mm pattern, capturing hours and minutes separately for each match.
# AM/PM indicator is optional.
> clock_times: regex.scanning('(\d{1,2}):(\d{2})( AM| PM)?')
function
# 1 match
> clock_times("It was 9:30 AM.")
[["9:30 AM", "9", "30", " AM"]]
# 2 matches, optional AM/PM indicator is missing on second match
> clock_times("The hen jumped over the fence at 10:32 PM, the fox followed at 10:42.")
[["10:32 PM", "10", "32", " PM"], ["10:42", "10", "42", nil]]
# no matches
> clock_times("Hello world!")
[]
> clock_times(nil)
nil
splitting
(string pattern, long limit=nil) -> function
Returns a function f
accepting one string argument x
and returning a list substrings of x
split on boundaries given by pattern
.
If limit
is positive, the pattern is applied limit-1
times, so at most limit
items are in the resulting list.
If limit
is negative, the pattern is applied as often as possible and there is no limit on the size of the resulting list.
If limit
is 0
or nil
, the pattern is applied as often as possible, and there is no limit on the size of the resulting list. Trailing
empty strings are removed from the list.
In case pattern
is not found in x
, f
returns a list containing only x
.
Calling f
with a nil
argument returns nil
.
Throws an error if pattern
is nil
or not a valid regular expression.\
# split on space
> f: regex.splitting(' ')
function
> f("Hello World!")
["Hello", "World!"]
# split on word boundary
> f: regex.splitting('\b')
function
> f("Hello World!")
["Hello", " ", "World", "!"]
# split on comma potentially followed by space
> f: regex.splitting(',( )?')
function
> f("some, CSV,data, here")
["some", "CSV", "data", "here"]
# split out 2 initial sections between dashes
> f: regex.splitting('-', 3)
function
> f("abc-def-xyhaiod-28734-as2")
["abc", "def", "xyhaiod-28734-as2"]
> f(nil)
nil
replacing
(string pattern, string replace) -> function
Returns a function f
accepting one string argument and returning a string replacing all occurrences of pattern
with replace
.
References to capturing groups in replace
are possible through $n
syntax, where n
is the number of the capturing group, as counted by
the occurrence of opening group parentheses. To replace a literal $n
, escape the $
sign as \$
.
Calling f
with a nil
argument returns nil
.
Throws an error if any argument is nil
or pattern
is not a valid regular expression.
# match date in yyyy/dd/mm format and convert to ISO date
> to_iso_date: regex.replacing('(\d{4})/(\d{2})/(\d{2})', '$1-$3-$2')
function
> to_iso_date("2017/24/05")
"2017-05-24"
> to_iso_date("hello")
"hello"
> to_iso_date(nil)
nil
> nr_dollar: regex.replacing('\b(a dollar)|(one dollar)\b', '\$1')
function
> nr_dollar("I need a dollar, just one dollar more.")
"I need $1, just $1 more."
quote
(string x) -> string
Returns a string in which each character of x
with special meaning in a pattern has been escaped.
The resulting string matches x
literally as a pattern.
Returns nil
if x
is nil
.
# splits by word boundary
> f: regex.splitting('\b')
function
> f('foo\bbar\bbaz')
["foo", "\\", "bbar", "\\", "bbaz"]
# splits by literal sequence of characters '\b'
> f: regex.splitting(regex.quote('\b'))
function
> f('foo\bbar\bbaz')
["foo", "bar", "baz"]
library data
The data library contains functions for manipulation of lists and dictionaries.
size
(any xs) -> long
Given a dict or list of xs
, returns the collection’s size.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a dict
nor a list
.
> data.size([])
0
> data.size([1,2,3])
3
> data.size({})
0
> data.size({:a "foo", :b "bar"})
2
> data.size(nil)
nil
> data.size("foo")
ERROR:
code: ILLEGAL_ARGUMENT
message: size is not defined for type string
empty?
(any xs) -> boolean
Given a dict or list of xs
, returns true if the collection is empty, false otherwise.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a dict
nor a list
.
> data.empty?([])
true
> data.empty?([1,2,3])
false
> data.empty?({})
true
> data.empty?({:a "foo", :b "bar"})
false
> data.empty?(nil)
nil
> data.empty?("foo")
ERROR:
code: ILLEGAL_ARGUMENT
message: empty? is not defined for type string
get
(xs, key, not_found) ->
Given a dict or list of xs
, and a key, returns xs[key]
if the key is present in xs
.
Returns not_found
if key
is not present in xs
.
Returns nil
if xs
is nil
, or key
is nil
.
Throws an error if xs
is neither a dict
nor a list
.
Throws an error if xs
is a list
and key
cannot be cast to a long
.
Throws an error if xs
is a dict
and key
cannot be cast to a string
.
> data.get(["a", "b", "c"], 0, "foo")
"a"
> data.get(["a", "b", "c"], 10, "foo")
"foo"
> data.get({:a "alpha", :b "beta"}, :a, "default")
"alpha"
> data.get({:a "alpha", :b "beta"}, :z, "default")
"default"
> data.get([], nil, "foo")
nil
> data.get(nil, :a, "foo")
nil
put
(xs, key, value) ->
Given a dict or list of xs
, returns the same type of collection with value
placed at key
.
If xs
is a list, any undefined indexes are filled with nil
.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a dict
nor a list
.
Throws an error if key
is nil
.
Throws an error if xs
is a list
and key
cannot be cast to a long
or key
is negative.
Throws an error if xs
is a dict
and key
cannot be cast to a string
.
> data.put([], 0, "foo")
["foo"]
> data.put(["bar"], 0, "foo")
["foo"]
> data.put(["bar"], 1, "foo")
["bar", "foo"]
> data.put(["bar"], 2, "foo")
["bar", nil, "foo"]
> data.put(["bar"], 10, "foo")
["bar", nil, nil, nil, nil, nil, nil, nil, nil, nil, "foo"]
> data.put({:a "foo", :b "bar"}, :c, "baz")
{
:a "foo",
:b "bar",
:c "baz"
}
> data.put({:a "foo", :b "bar"}, :a, "baz")
{
:a "baz",
:b "bar"
}
> data.put(nil, 0, "baz")
nil
get_in
(any xs, list keys, any not_found) ->
Accesses nested list
and dict
values in xs
using the list of keys
. Returns the found value.
Returns not_found
if one of the keys is not present.
Returns nil
if xs
is nil
, or keys
is nil
.
Returns xs
if keys
is empty.
Throws an error if xs
or an accessed nested structure is neither a dict
nor a list
.
Throws an error if xs
or an accessed nested structure is a list
and the key cannot be cast to a long
.
Throws an error if xs
or an accessed nested structure is a dict
and the key cannot be cast to a string
.
> data.get_in([["a", "b"], ["c", "d"], ["e", "f"]], [2, 0], "foo")
"e"
> data.get_in([["a", "b"], ["c", "d"], ["e", "f"]], [8, 0], "foo")
"foo"
> data.get_in([{:name "alpha"}, {:name "beta"}, {:name "gamma"}], [1, :name], "foo")
"beta"
> data.get_in({:a [1,2,3], :b [4,5,6]}, [:b 1], "default")
5
> data.get_in([1, 2, 3], [], "foo")
[1, 2, 3]
> data.get_in(nil, [0], "foo")
nil
> data.get_in([1,2,3], nil, "foo")
nil
> data.get_in({:a [1,2,3], :b [4,5,6]}, [:b :c], "default")
ERROR:
code: CAST_ERROR
message: Cannot cast c to long
put_in
(xs, list keys, value) ->
Given a dict or list of xs
, returns the same type of collection with value
placed at the end of navigating
through the list of keys
.
If any intermediate structures have to be created, they will be, depending on key type. String keys create dicts. Long keys create lists.
If a value is placed in a list, any undefined indexes are filled with nil
.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a dict
nor a list
.
Throws an error if xs
is a dict
or a list
and keys
is nil
.
Throws an error if navigating into a list
and the key cannot be cast to a long
or the key is negative.
Throws an error if navigating into a dict
and the key cannot be cast to a string
.
> \e
data.put_in(
{
"1" {:name "adam"},
"2" {:name "jane"}
},
[2, :name],
"eve"
)
\e
{
:`1` {
:name "adam"
},
:`2` {
:name "eve"
}
}
> data.put_in([], [0, :a], "foo")
[{
:a "foo"
}]
> data.put_in([], [0, :a, 2], "foo")
[{
:a [nil, nil, "foo"]
}]
> data.put_in({}, [:a, :b, :c], "foo")
{
:a {
:b {
:c "foo"
}
}
}
> data.put_in(nil, [0], "baz")
nil
update
(xs, key, function f)
Given a dict or list of xs
, returns the same type of collection with f(v)
placed at key
, where v
is the original value found at key
.
If xs
is a list, any undefined indexes are filled with nil
.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a dict
nor a list
.
Throws an error if key
is nil
.
Throws an error if f
is nil
.
Throws an error if xs
is a list
and key
cannot be cast to a long
or key
is negative.
Throws an error if xs
is a dict
and key
cannot be cast to a string
.
> data.update(["a", "b", "c"], 0, (x) -> x.."-updated")
["a-updated", "b", "c"]
> data.update(["a", "b", "c"], 5, (x) -> "original was: "..x)
["a", "b", "c", nil, nil, "original was: nil"]
> data.update({:a "foo", :b "bar"}, :a, (x) -> "Mr. "..x)
{
:a "Mr. foo",
:b "bar"
}
> data.update(nil, 0, (x) -> x)
nil
update_in
(xs, list keys, function f) ->
Given a dict or list of xs
, returns the same type of collection with f(v)
placed at the end of navigating
through the list of keys
, where v
is the value originally found.
If any intermediate structures have to be created, they will be, depending on key type. String keys create dicts. Long keys create lists.
If a value is placed in a list, any undefined indexes are filled with nil
.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a dict
nor a list
.
Throws an error if xs
is a dict
or a list
and keys
is nil
.
Throws an error if f
is nil
.
Throws an error if navigating into a list
and the key cannot be cast to a long
or the key is negative.
Throws an error if navigating into a dict
and the key cannot be cast to a string
.
> \e
data.update_in(
{
"1" {:name "adam"},
"2" {:name "jane"}
},
[2, :name],
(x) -> "miss "..x
)
\e
{
:`1` {
:name "adam"
},
:`2` {
:name "miss jane"
}
}
> data.update_in([], [0, :a], (x) -> "updated: "..x)
[{
:a "updated: nil"
}]
> data.update_in({:even [0, 2, 4, 6], :odd [1, 3, 5, 7]}, [:even, 3], (x) -> x*2)
{
:odd [1, 3, 5, 7],
:even [0, 2, 4, 12]
}
> data.update_in(nil, [0], (x) -> x+1)
nil
keys
(xs) -> list
Given a list
or dict
of xs
, returns a list of keys present in the structure. If xs
is a list present indexes are returned in order. If xs
is a dict, the order of returned keys is undefined.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
> data.keys([])
[]
> data.keys(["a", nil, "c"])
[0, 1, 2]
> data.keys({})
[]
> data.keys({:a "foo", :b "bar"})
["a", "b"]
> data.keys(nil)
nil
> data.keys("foo")
ERROR:
code: ILLEGAL_ARGUMENT
message: keys is not defined for type string
has?
(xs, key) -> boolean
Returns true
if key
is a key in xs
, false otherwise.
If xs
is a list
, key
is cast to a long
.
If xs
is a dict
, key
is cast to a string
.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
, nor a dict
.
> data.has?(["a", "b", "c"], 2)
true
> data.has?(["a", "b", "c"], 3)
false
> data.has?([nil, nil, nil], 1)
true
> data.has?({:a "foo", :b "bar"}, :a)
true
> data.has?({:a "foo", :b "bar"}, :c)
false
> data.has?({:a "foo", :b "bar", :c nil}, :c)
true
> data.has?("foo", 1)
ERROR:
code: ILLEGAL_ARGUMENT
message: has? is not defined for type string
> data.has?("foo" as list, 1)
true
values
(xs) -> list
Given a list
or dict
of xs
, returns a list of values present in the structure. Returns xs
if xs
is a list . If xs
is a dict, the order of returned values is undefined.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
> data.values([])
[]
> data.values(["a", nil, "c"])
["a", nil, "c"]
> data.values({})
[]
> data.values({:a "foo", :b "bar"})
["foo", "bar"]
> data.values(nil)
nil
> data.values("foo")
ERROR:
code: ILLEGAL_ARGUMENT
message: values is not defined for type string
entries
(dict xs) -> list
Returns a list
where each element is a dict
. For each key k
in xs
there is a correpsonding element {:key k, :value xs[k]}
in the list
. The order of items in the list
is undefined.
Returns nil
if xs
is nil
.
> data.entries({})
[]
> data.entries({:foo "bar"})
[{
:value "bar",
:key "foo"
}]
> data.entries({:a 1, :b 2})
[{
:value 1,
:key "a"
}, {
:value 2,
:key "b"
}]
> data.entries(nil)
nil
prepend
(x, list xs) -> list
Returns a list consisting of x
followed by all elements of xs
.
Returns nil
if xs
is nil
.
> data.prepend("a", ["b", "c"])
["a", "b", "c"]
> data.prepend("a", [])
["a"]
> data.prepend("a", nil)
nil
append
(list xs, x) -> list
Returns a list consisting of all elements of xs
followed by x
.
Returns nil
if xs
is nil
.
> data.append(["a", "b"], "c")
["a", "b", "c"]
> data.append([], "a")
["a"]
> data.append(nil, "a")
nil
find
(list xs, function p) ->
Tests each x
in xs
in order by passing them to predicate function p
.
If p
accepts a single argument, p(x)
is evaluated.
If p
accepts two arguments, p(x, i)
is evaluated, where i
is the index of x
in xs
.
Returns the first x
for which p
evaluates to a value that casts to boolean
true
.
Returns nil
if there is no x
in xs
such that p
evaluates to a value that casts to boolean
true
.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.find([1, 2, 3, 4, 5], (x) -> x >= 3)
3
# find first even number on an even index
> data.find([1, 2, 1, 7, 6, 5, 3], (x, i) -> (i % 2 == 0) && (x % 2 == 0))
6
> data.find([1, 2, 3, 4, 5], (x) -> x >= 10)
nil
> data.find(nil, (x) -> true)
nil
> data.find([], nil)
code: NIL_ERROR
message: predicate function cannot be nil
find_index
(list xs, function p) -> long
Tests each x
in xs
in order by passing them to predicate function p
.
If p
accepts a single argument, p(x)
is evaluated.
If p
accepts two arguments, p(x, i)
is evaluated, where i
is the index of x
in xs
.
Returns the first index for which p
evaluates to a value that casts to boolean
true
.
Returns nil
if there is no x
in xs
such that p
evaluates to a value that casts to boolean
true
.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.find_index([1, 2, 3, 4, 5], (x) -> x >= 3)
2
# find index of first even number on an even index
> data.find_index([1, 2, 1, 7, 6, 5, 3], (x, i) -> (i % 2 == 0) && (x % 2 == 0))
4
> data.find_index([1, 2, 3, 4, 5], (x) -> x >= 10)
nil
> data.find_index(nil, (x) -> true)
nil
> data.find_index([], nil)
ERROR:
code: NIL_ERROR
message: predicate function cannot be nil
find_last
(list xs, function p) ->
Tests each x
in xs
in reverse order by passing them to predicate function p
.
If p
accepts a single argument, p(x)
is evaluated.
If p
accepts two arguments, p(x, i)
is evaluated, where i
is the index of x
in xs
.
Starting from the end of the list returns the first x
for which p
evaluates to a value that casts to boolean
true
.
Returns nil
if there is no x
in xs
such that p
evaluates to a value that casts to boolean
true
.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.find_last([1, 2, 3, 4, 5], (x) -> x <= 3)
3
# find last even number on an even index
> data.find_last([1, 2, 1, 7, 6, 5, 8, 4], (x, i) -> (i % 2 == 0) && (x % 2 == 0))
8
> data.find_last([1, 2, 3, 4, 5], (x) -> x >= 10)
nil
> data.find_last(nil, (x) -> true)
nil
> data.find_last([], nil)
code: NIL_ERROR
message: predicate function cannot be nil
find_last_index
(list xs, function p) -> long
Tests each x
in xs
in reverse order by passing them to predicate function p
.
If p
accepts a single argument, p(x)
is evaluated.
If p
accepts two arguments, p(x, i)
is evaluated, where i
is the index of x
in xs
.
Starting from the end of the list, returns the first index for which p
evaluates to a value that casts to boolean
true
.
Returns nil
if there is no x
in xs
such that p
evaluates to a value that casts to boolean
true
.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.find_last_index([1, 2, 3, 4, 5], (x) -> x <= 3)
2
# find index of last even number on an even index
> data.find_last_index([1, 2, 1, 7, 6, 5, 8, 4], (x, i) -> (i % 2 == 0) && (x % 2 == 0))
6
> data.find_last_index([1, 2, 3, 4, 5], (x) -> x >= 10)
nil
> data.find_last_index(nil, (x) -> true)
nil
> data.find_last_index([], nil)
ERROR:
code: NIL_ERROR
message: predicate function cannot be nil
insert
(list xs, long i, v) ->
Returns a list consisting of all elements of xs
, with elements starting at index i
shifted to the right, and v
inserted at position i
.
If i
is bigger than the largest index in xs
, any intermediate indexes are created with value nil
.
Returns nil
if xs
is nil.
Throws an error if index is negative or nil
.
> data.insert([], 0, "a")
["a"]
> data.insert(["a", "b", "d"], 2, "c")
["a", "b", "c", "d"]
> data.insert([], 3, "a")
[nil, nil, nil, "a"]
> data.insert(nil, 0, "a")
nil
> data.insert([], -2, "a")
ERROR:
code: INDEX_OUT_OF_BOUNDS
message: cannot insert at index -2
> data.insert([], nil, "a")
ERROR:
code: NIL_ERROR
message: cannot insert at nil index
delete
(xs, key) ->
Given a list
or dict
xs
, returns a collection of the same type consisting of all elements of xs
, except for the element at key
.
If xs
is a list, any elements past the deleted index are shifted to the left.
If xs
does not have the given key
, xs
is returned.
Returns nil
if xs
is nil.
Returns xs
if key
is nil
.
Throws an error if xs
is a list and key
cannot be cast to a long
.
Throws an error if xs
is a dict and key
cannot be cast to a string
.
> data.delete(["a", "b", "c"], 0)
["b", "c"]
> data.delete(["a", "b", "c"], 1)
["a", "c"]
> data.delete(["a", "b", "c"], 10)
["a", "b", "c"]
> data.delete({:a "1", :b "2"}, :a)
{
:b "2"
}
> data.delete(nil, 0)
nil
> data.delete([0, 1], nil)
[0, 1]
> data.delete([], -2)
ERROR:
code: INDEX_OUT_OF_BOUNDS
message: cannot delete index -2
select
(xs, list keys, not_found) ->
Given a list
or dict
xs
, returns a collection of the same type, with elements at all keys
from xs
.
If any key
is not present in xs
, not_found
is included in the result instead.
Returns nil
if xs
is nil
or keys
is nil
.
Throws an error if xs
is a list
and a key
cannot be cast to long
.
Throws an error if xs
is a dict
and a key
cannot be cast to string
.
> data.select(["a", "b", "c"], [0, 2])
["a", "c"]
> data.select(["a", "b", "c"], [0, 2, 10])
["a", "c", nil]
> data.select(["a", "b", "c"], [0, 2, 10], "z")
["a", "c", "z"]
> data.select({:a "1", :b "2", :c "3"}, [:a, :c, :d], "0")
{
:a "1",
:c "3",
:d "0"
}
> data.select(nil, [0, 1])
nil
> data.select([0, 1], nil)
nil
pluck
(xs, key) ->
Given a list
or dict
xs
, returns a collection of the same type and of the same size.
Each element el
of xs
must be a list
, dict
, or nil
. The given key
is extracted
from each el
and placed in the corresponding position in the result. If key
is not
present in el
, nil
is extracted.
Returns nil
if xs
is nil
or key
is nil
.
Throws an error if key
cannot be cast to string
or long
when indexing into elements of
type dict
or list
.
Throws an error if any element of xs
is not a dict
, list
, or nil
.
> data.pluck([{:id 1, :name "Sherlock", :address "221B Baker Street" }, {:id 2, :name "Bruce", :address "1007 Mountain Drive"}], "name")
["Sherlock", "Bruce"]
> data.pluck([["a", "b"], ["c", "d"]], 0)
["a", "c"]
> data.pluck([["a", "b"], ["c"], ["d", "e"]], 1)
["b", nil, "e"]
> data.pluck({:roll_1 [2, 4], :roll_2 [6, 5], :roll_3 [1, 3]}, 0)
{:roll_1 2, :roll_2 6, :roll_3 1}
> data.pluck(nil, 0)
nil
> data.pluck([{:a 1, :b 2}, {:a 3, :b 4}], nil)
nil
omit
(dict xs, list keys) ->
Returns a copy of xs
in which all keys given in keys
are omitted.
Returns nil
if xs
is nil
or keys
is nil
.
Throws an error if any key in keys
cannot be cast to string
.
> data.omit({:a 1, :b 2, :c 3}, ["a", "c"])
{
:b 2
}
> data.omit({:a 1, :b 2, :c 3}, ["a", "foo"])
{
:b 2,
:c 3
}
> data.omit(nil, ["a"])
nil
> data.omit({:a 1, :b 2}, nil)
nil
filter
(xs, function p) ->
Given a list
or dict
xs
, returns a collection of the same type,
with all elements for which predicate function p
returns a value that casts to boolean
true
.
If p
accepts one argument, x
is passed. If p
accepts two arguments, x
and the key or index of x
in xs
is passed.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if p
is nil
.
> data.filter([0,1,2,3,4,5,6,7,8], (x) -> x % 2 == 0)
[0, 2, 4, 6, 8]
> data.filter(["a", "b", "c", "d", "e", "f", "g"], (x, i) -> i % 2 == 0)
["a", "c", "e", "g"]
> data.filter({:a 1, :b 2, :c 3, :d 4, :e 5, :f 6}, (x) -> x % 3 == 0)
{
:c 3,
:f 6
}
> data.filter({:a 1, :b 2, :c 3, :d 4, :e 5, :f 6}, (x, k) -> k == "d" || x % 3 == 0)
{
:c 3,
:d 4,
:f 6
}
> data.filter(nil, (x) -> true)
nil
> data.filter([], nil)
ERROR:
code: NIL_ERROR
message: predicate function cannot be nil
> data.filter(1, (x) -> true)
ERROR:
code: ILLEGAL_ARGUMENT
message: filter is not defined for type long
shuffle
(list xs, seed) -> list
Returns a list with all elements of xs
in random order. The reordering of items is based on seed
.
The same seed will shuffle lists of equal length in the same way.
Returns nil
if xs
is nil
.
> data.shuffle([1, 2, 3, 4, 5, 6], "hello")
[5, 2, 6, 4, 1, 3]
> data.shuffle(["a", "b", "c", "d", "e", "f"], "hello")
["e", "b", "f", "d", "a", "c"]
> data.shuffle([1, 2, 3, 4, 5, 6], "foo")
[1, 5, 2, 4, 3, 6]
> data.shuffle(["a", "b", "c", "d", "e", "f"], "foo")
["a", "e", "b", "d", "c", "f"]
> data.shuffle(nil, "seed")
nil
choice
(list xs, seed) -> any
Returns a random item from xs
. The selection is based on seed
.
The same seed will consistently select the same index from same-length lists.
Returns nil
if xs
is nil
or empty.
> data.choice([1, 2, 3, 4, 5, 6], "foo")
1
> data.choice([1, 2, 3, 4, 5, 6], "bar")
6
> data.choice([1, 2, 3, 4, 5, 6], "seed")
2
> data.choice([], "seed")
nil
> data.choice(nil, "seed")
nil
sample
(list xs, long count, boolean with_return, seed) -> list
Returns a random selection of count
items from random indexes in xs
. The selection is based on seed
.
The same seed will consistently select the same indexes from same-length lists.
If with_return
is true
, indexes can be selected multiple times. If with_return
is false
,
each index in xs
can be selected only once.
In case with_return
is false
and count
is larger than the number of items in xs
, the returned list is
limited in length to the number of items available.
Returns an empty list if count
is negative.
Returns nil
if xs
is nil
, count
is nil
, or with_return
is nil
.
> data.sample([1, 2, 3, 4, 5, 6], 4, true, "seed")
[2, 5, 5, 2]
> data.sample([1, 2, 3, 4, 5, 6], 4, false, "seed")
[4, 1, 6, 3]
> data.sample([1, 2, 3, 4, 5, 6], 10, true, "seed")
[2, 5, 5, 2, 5, 2, 6, 4, 4, 6]
> data.sample([1, 2, 3, 4, 5, 6], 10, false, "seed")
[4, 1, 6, 3, 5, 2]
> data.sample([1, 2, 3, 4, 5, 6], 10, true, "foo")
[1, 3, 6, 4, 2, 3, 3, 5, 1, 5]
> data.sample([1, 2, 3, 4, 5, 6], 10, false, "foo")
[3, 4, 5, 2, 6, 1]
unique
(list xs) -> list
Returns a list with all duplicates in xs
removed. Values are considered duplicates when they compare as equal
using the ===
operator.
Returns nil
if xs
is nil
.
> data.unique([1, 1, 2, 3, 3])
[1, 2, 3]
> data.unique([1.0, 1, 2.0, 2, 3.0, 3])
[1.0, 1, 2.0, 2, 3.0, 3]
> data.unique(["foo", "bar", "foo"])
["foo", "bar"]
> data.unique([{:a "a", :b "b"}, {:b "b", :a "a"}])
[{
:a "a",
:b "b"
}]
> data.unique(nil)
nil
range
(long start=0, long end=0) -> list
Returns a list with long values starting at start
, and ending at end
.
Returns an empty list if start > end
.
Returns nil
if start
is nil
or end
is nil
.
> data.range(0, 2)
[0, 1, 2]
> data.range(-3, 3)
[-3, -2, -1, 0, 1, 2, 3]
> data.range(1, 1)
[1]
> data.range(10, 1)
[]
> data.range(nil, 0)
nil
> data.range(0, nil)
nil
any?
(list xs, function p) -> boolean
Tests items x
in xs
with predicate function p
. If p
accepts one argument, x
is passed. If p
accepts
two arguments, x
and the index of x
in xs
are passed.
Returns true if p
returns a value that casts to boolean true
for any x
in xs
.
Returns false otherwise.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.any?([1,2,3,4,5], (x) -> x % 2 == 0)
true
> data.any?([1,3,5], (x) -> x % 2 == 0)
false
> data.any?([1,3,5], (x, i) -> x == i)
false
> data.any?([1,0,2], (x, i) -> x == i)
true
> data.any?([], (x) -> true)
false
> data.any?(nil, (x) -> true)
nil
none?
(list xs, function p) -> boolean
Tests items x
in xs
with predicate function p
. If p
accepts one argument, x
is passed. If p
accepts
two arguments, x
and the index of x
in xs
are passed.
Returns false if p
returns a value that casts to boolean true
for any x
in xs
.
Returns true otherwise.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.none?([1,2,3,4,5], (x) -> x % 2 == 0)
false
> data.none?([1,3,5], (x) -> x % 2 == 0)
true
> data.none?([1,3,5], (x, i) -> x == i)
true
> data.none?([1,0,2], (x, i) -> x == i)
false
> data.none?([], (x) -> true)
true
> data.none?(nil, (x) -> true)
nil
all?
(list xs, function p) -> boolean
Tests items x
in xs
with predicate function p
. If p
accepts one argument, x
is passed. If p
accepts
two arguments, x
and the index of x
in xs
are passed.
Returns true if p
returns a value that casts to boolean true
for all x
in xs
.
Returns true if xs
is empty.
Returns false otherwise.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.all?([1,2,3,4,5], (x) -> x % 2 == 0)
false
> data.all?([2,4,6], (x) -> x % 2 == 0)
true
> data.all?([1,3,5], (x, i) -> x == i)
false
> data.all?([0,1,2], (x, i) -> x == i)
true
> data.all?([], (x) -> false)
true
> data.all?(nil, (x) -> false)
nil
init
(list xs) -> list
Returns a list containing all elements of xs
with the exception of the last one.
Returns nil
if xs
is nil
.
Throws an error if xs
is empty.
> data.init([1,2,3])
[1, 2]
> data.init(nil)
nil
> data.init([])
ERROR:
code: ILLEGAL_ARGUMENT
message: list must not be empty
tail
(list xs) -> list
Returns a list containing all elements of xs
with the exception of the first one.
Returns nil
if xs
is nil
.
Throws an error if xs
is empty.
> data.tail([1,2,3])
[2, 3]
> data.tail(nil)
nil
> data.tail([])
ERROR:
code: ILLEGAL_ARGUMENT
message: list must not be empty
head
(list xs) -> any
Returns the first element in xs
.
Returns nil
if xs
is nil
.
Throws an error if xs
is empty.
> data.head([1,2,3])
1
> data.head(nil)
nil
> data.head([])
ERROR:
code: ILLEGAL_ARGUMENT
message: list must not be empty
last
(list xs) -> any
Returns the last element in xs
.
Returns nil
if xs
is nil
.
Throws an error if xs
is empty.
> data.last([1,2,3])
3
> data.last(nil)
nil
> data.last([])
ERROR:
code: ILLEGAL_ARGUMENT
message: list must not be empty
slice
(list xs, long start=0, long end=nil) -> list
Returns a sublist of xs
starting at index start
inclusively, and extending to index end
exclusively.
If end
is nil
, the sublist extends to the end of xs
.
Returns an empty list if start
is greater than the last index in xs
.
Returns an empty list if start >= end
.
Returns nil
if xs
is nil
.
Throws an error if start
is nil
or start < 0
.
> data.slice([1,2,3,4,5], 3)
[4, 5]
> data.slice(["a", "b", "c", "d", "e"], 1, 4)
["b", "c", "d"]
> data.slice(["a", "b"], 10, 20)
[]
> data.slice([1,2,3], 1, 1)
[]
> data.slice(nil, 0, 1)
nil
slices
(list xs, long s=1) -> list
Partitions xs
into slices. Returns a list of slices, each of size s
. The last slice may contain less than s
items.
Returns an empty list if xs
is empty.
Returns nil
if any argument is nil
.
Throws an error if s <= 0
.
> data.slices([1,2,3,4,5,6,7,8,9,0], 3)
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [0]]
> data.slices(nil)
nil
> data.slices([])
[]
> data.slices([], 4)
[]
> data.slices([1,2,3], 0)
ERROR:
code: CUSTOM_ERROR
message: CUSTOM_ERROR
at: std.tf:2109:20
source: throw {:message "s must be positive, was #{s}" :code "ILLEGAL_ARGUMENT"}
value: {
:message "s must be positive, was 0",
:code "ILLEGAL_ARGUMENT"
}
reverse
(list xs) -> list
Returns a list that contains all elements of xs
in reverse order.
Returns nil
if xs
is nil
.
> data.reverse([1, 2, 3])
[3, 2, 1]
> data.reverse(nil)
nil
sort
(list xs, function f) -> list
Returns a list sorted according to comparator function f. The sorting algorithm is guaranteed to be stable.
The comparator function accepts two arguments: a and b.
If a < b, f returns a negative number.
If a > b, f returns a positive number.
If a == b, f returns 0.
Returns nil
if any argument is nil
.
> data.sort([1, 4, 5, 3, 6, 7], math.compare)
[1, 3, 4, 5, 6, 7]
# sorts numbers by numeric value
> data.sort([110, 221, 12, 121, 222, 33], math.compare)
[12, 33, 110, 121, 221, 222]
# sorts numbers as strings
> data.sort([12, 33, 110, 121, 221, 222], strings.comparator())
[110, 12, 121, 221, 222, 33]
# sorts records by id
> data.sort([{:id 872, :name "foo"}, {:id 261, :name "bar"}], (a, b) -> math.compare(a[:id], b[:id]))
[{
:name "bar",
:id 261
}, {
:name "foo",
:id 872
}]
repeat
(long n, x) -> list
Returns a list of length n
that contains x
in every position.
Returns nil
if n
is nil
.
Throws an error if n
is negative.
> data.repeat(3, "foo")
["foo", "foo", "foo"]
> data.repeat(0, "foo")
[]
> data.repeat(nil, "foo")
nil
> data.repeat(-2, "foo")
ERROR:
code: INDEX_OUT_OF_BOUNDS
message: Cannot repeat -2 times
concat
(list lists) -> list
Returns a list that contains all elements of all lists
. Lists are concatenated in given order.
Returns nil
if lists
is nil
.
Returns nil
if any element of lists
is nil
.
Throws an error if any element of lists
is not a list
.
> data.concat([[1,2,3], [4,5,6], [7,8,9]])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
> data.concat([[1,nil,3], [nil,5,6], [7,nil,nil]])
[1, nil, 3, nil, 5, 6, 7, nil, nil]
> data.concat([[1,2,3], nil, [7,8,9]])
nil
> data.concat(nil)
nil
> data.concat(["foo", "bar"])
ERROR:
code: ILLEGAL_ARGUMENT
message: cannot concat type string
merge
(list dicts) -> dict
Returns a dict
that contains all entries from all given dicts
. Dicts are merged left to right.
In case of duplicate keys across dicts
, the rightmost occurrence takes precedence.
Returns nil
if dicts
is nil
.
Returns nil
if any element of dicts
is nil
.
Throws an error if any element of dicts
is not a dict
.
> data.merge([{:a 1}, {:b 2}, {:c 3}])
{
:a 1,
:b 2,
:c 3
}
> data.merge([{:a 1}, {:b 2}, {:a 99}])
{
:a 99,
:b 2
}
> data.merge([{:a 1}, nil])
nil
> data.merge(nil)
nil
> data.merge(["foo", "bar"])
ERROR:
code: ILLEGAL_ARGUMENT
message: cannot merge type string
take
(long n, list xs) -> list
Returns a list containing the first n
elements of xs
.
Returns xs
if n
is greater than the size of xs
.
Returns an empty list if n
is negative.
Returns nil
if n
is nil
or xs
is nil
.
> data.take(2, ["a", "b", "c", "d"])
["a", "b"]
> data.take(10, ["a", "b"])
["a", "b"]
> data.take(0, ["a", "b", "c"])
[]
> data.take(-1, ["a", "b", "c"])
[]
> data.take(1, nil)
nil
> data.take(nil, ["a", "b", "c"])
nil
take_while
(function p, list xs) -> list
Returns a list containing leading elements x
of xs
for which the predicate function p
returns a value that casts to boolean true
.
If p
accepts one argument, x
is passed. If p
accepts two arguments, x
and the index of x
are passed.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.take_while((x) -> x < 5, [2, 3, 3, 2, 5, 1, 2])
[2, 3, 3, 2]
> data.take_while((x) -> x % 2 == 0, [0, 2, 4, 6, 7, 8, 9, 10])
[0, 2, 4, 6]
> data.take_while((x) -> x % 2 == 0, [1, 2, 3, 4])
[]
> data.take_while((x) -> true, nil)
nil
take_until
(function p, list xs) -> list
Returns a list containing leading elements x
of xs
for which the predicate function p
returns a value that does not cast to boolean true
.
If p
accepts one argument, x
is passed. If p
accepts two arguments, x
and the index of x
are passed.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.take_until((x) -> x >= 5, [2, 3, 3, 2, 5, 1, 2])
[2, 3, 3, 2]
> data.take_until((x) -> x % 2 != 0, [0, 2, 4, 6, 7, 8, 9, 10])
[0, 2, 4, 6]
> data.take_until((x) -> x % 2 != 0, [1, 2, 3, 4])
[]
> data.take_until((x) -> x > 10, [1, 2, 3, 4])
[1, 2, 3, 4]
> data.take_until((x) -> false, nil)
nil
drop
(long n, list xs) -> list
Returns a list of elements in xs
skipping the first n
elements.
Returns an empty list if n
is greater than the size of xs
.
Returns xs
if n
is negative.
Returns nil
if n
is nil
or xs
is nil
.
> data.drop(2, ["a", "b", "c", "d"])
["c", "d"]
> data.drop(10, ["a", "b"])
[]
> data.drop(0, ["a", "b", "c"])
["a", "b", "c"]
> data.drop(-3, ["a", "b", "c"])
["a", "b", "c"]
> data.drop(1, nil)
nil
> data.drop(nil, ["a", "b", "c"])
nil
drop_while
(function p, list xs) -> list
Returns a sublist of elements of xs
skipping leading elements x
for which the predicate function p
returns a value that casts to boolean true
.
If p
accepts one argument, x
is passed. If p
accepts two arguments, x
and the index of x
are passed.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.drop_while((x) -> x <= 2, [1, 2, 3, 4])
[3, 4]
> data.drop_while((x) -> x > 10, [1, 2, 3])
[1, 2, 3]
> data.drop_while((x) -> false, nil)
nil
drop_until
(function p, list xs) -> list
Returns a sublist of elements of xs
skipping leading elements x
for which the predicate function p
returns a value that does not cast to boolean true
.
If p
accepts one argument, x
is passed. If p
accepts two arguments, x
and the index of x
are passed.
Returns nil
if xs
is nil
.
Throws an error if p
is nil
.
> data.drop_until((x) -> x > 2, [1, 2, 3, 4])
[3, 4]
> data.drop_until((x) -> x <= 2, [1, 2, 3, 4])
[1, 2, 3, 4]
> data.drop_until((x) -> x > 10, [1, 2, 3, 4])
[]
> data.drop_until((x) -> false, nil)
nil
contains?
(xs, x) -> boolean
If xs
is a list
, returns true
if for any element e
of xs
x === e
evaluates to true
, false
otherwise.
If xs
is a dict
, returns true
if for any value v
in xs
v === e
evaluates to true
, false
otherwise.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
> data.contains?([1,2,3], 2)
true
> data.contains?([1,2,3], 4)
false
> data.contains?({:a 1, :b 2, :c 3}, 2)
true
> data.contains?({:a 1, :b 2, :c 3}, 4)
false
# NaN never compares as equal
> data.contains?([NaN], NaN)
false
# functions never compare as equal
> let {f: () -> true;} data.contains?([f], f)
false
> data.contains?(nil, 0)
nil
> data.contains?("foo", "bar")
ERROR:
code: ILLEGAL_ARGUMENT
message: contains? is not defined for type string
...
index_of
(list xs, x, long start=0) -> long
If xs
contains x
at or after index start
returns the index of the earliest such occurrence. Returns -1
if x
is not an element of xs
. Each element of xs
is compared to x
using the ===
operator.
Returns nil
if xs
is nil
.
Returns nil
if start
is nil
.
> data.index_of([1,2,3], 2)
1
# 2 !== 2.0
> data.index_of([1,2,3], 2.0)
-1
> data.index_of([1,2,3], 4)
-1
> data.index_of([1,2,3], 2, 2)
-1
> data.index_of([1,2,3,1,2,3], 3, 4)
5
# NaN === NaN is false
> data.index_of([NaN], NaN)
-1
# f === f is false for functions
> let {f: () -> true;} data.index_of([f], f)
-1
> data.index_of(nil, 2)
nil
> data.index_of([1,2,3], 3, nil)
nil
last_index_of
(list xs, x, long end=nil) -> long
If xs
contains x
at or before index end
returns the index of the last such occurrence. Returns -1
if x
is not an element of xs
. Each element of xs
is compared to x
using the ===
operator.
If end
is nil
, it is interpreted as the last index of xs
.
Returns nil
if xs
is nil
.
> data.last_index_of([1,2,3], 2)
1
> data.last_index_of([1,2,3,1,2,3], 2)
4
> data.last_index_of([1,2,3,1,2,3], 2, 4)
4
> data.last_index_of([1,2,3,1,2,3], 2, 3)
1
> data.last_index_of([1,2,3], 4)
-1
> data.last_index_of([1,2,3,1,2,3], 3, 1)
-1
# 2 !== 2.0
> data.last_index_of([1,2,3], 2.0)
-1
# NaN === NaN is false
> data.last_index_of([NaN], NaN)
-1
# f === f is false for functions
> let {f: () -> true;} data.last_index_of([f], f)
-1
> data.last_index_of(nil, 2)
nil
key_of
(dict xs, x) -> string
If xs
contains an entry with value x
, returns the key of that entry.
If there are multiple such entries, it is undefined which of the keys is returned.
Each value in xs
is compared to x
using the ===
operator.
Returns nil
if xs
does not contain an entry with value x
.
Returns nil
if xs
is nil
.
> data.key_of({:a 1, :b 2}, 1)
"a"
> data.key_of({:a 1, :b 2}, 3)
nil
> data.key_of({:foo 1, :bar 1}, 1)
"foo"
> data.key_of({:foo 1, :doo 1}, 1)
"doo"
# NaN === NaN is false
> data.key_of({:foo NaN}, NaN)
nil
# f === f is false, functions do not compare as equal
> let {f: () -> true;} data.key_of({:f f}, f)
nil
> data.key_of(nil, 1)
nil
flatten
(list xs) -> list
Builds a result list iterating over all elements x
in xs
. If x
is a list, it is concatenated to the result list.
Otherwise the element is appended to the list. Returns the result list.
Returns nil
if xs
is nil
.
> data.flatten([[1, 2, 3], 4, 5, [6, 7, 8]])
[1, 2, 3, 4, 5, 6, 7, 8]
> data.flatten([1, 2, 3])
[1, 2, 3]
> data.flatten([1, nil, [], "foo"])
[1, nil, "foo"]
> data.flatten([[[1]], [[2]]])
[[1], [2]]
> data.flatten(nil)
nil
map
(xs, function f) -> any
If xs
is a list
, returns a list
of all x
in xs
mapped through f
.
If f
accepts one argument, x
is passed.
If f
accepts two arguments, x
and its index are passed.
If xs
is a dict
, returns a dict
of all entries mapped through f
.
If f
accepts one argument, each entry’s value is passed.
If f
accepts two arguments, each entry’s value and key are passed.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if f
is nil
;
> data.map([1,2,3], (x) -> x*x)
[1, 4, 9]
> data.map(["a", "b", "c"], (x, i) -> i.." -> "..x)
["0 -> a", "1 -> b", "2 -> c"]
> data.map({:a 1, :b 2, :c 3}, (x) -> x*x)
{
:a 1,
:b 4,
:c 9
}
> data.map({:a 1, :b 2, :c 3}, (x, k) -> k.." -> "..x)
{
:a "a -> 1",
:b "b -> 2",
:c "c -> 3"
}
> data.map(nil, (x) -> x)
nil
> data.map([1, 2, 3], nil)
nil
> data.map("foo", (x) -> x)
ERROR:
code: ILLEGAL_ARGUMENT
message: map is not defined for type string
flatmap
(xs, function f) -> list
Expects xs
to be a list
or a dict
. Builds a result list by mapping each x
of xs
through f
. If a mapped value is a list, it is concatenated at the end of the result list.
Non-lists are appended to the result list.
If f
accepts a single argument, x
is passed.
If f
accepts two arguments, x
and its index or key are passed.
Returns the result list.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if f
is nil
.
> data.flatmap([1, 2, 3], (x) -> data.repeat(x, x))
[1, 2, 2, 3, 3, 3]
> data.flatmap([1, 2, 1], (x) -> if x == 1 then ["a", "b", "c"] else "-")
["a", "b", "c", "-", "a", "b", "c"]
> data.flatmap(nil, (x) -> x)
nil
> data.flatmap("foo", (x) -> x)
ERROR:
code: ILLEGAL_ARGUMENT
message: map is not defined for type string
...
mapcat
(xs, function f) -> list
Expects xs
to be a list
or a dict
. Builds a result list by mapping each x
of xs
through f
. If a mapped value is a list, it is concatenated at the end of the result list.
Non-lists are discarded.
If f
accepts a single argument, x
is passed.
If f
accepts two arguments, x
and its index or key are passed.
Returns the result list.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if f
is nil
.
> data.mapcat([1, 2, 3], (x) -> data.repeat(x, x))
[1, 2, 2, 3, 3, 3]
> data.mapcat([1, 2, 1], (x) -> if x == 1 then ["a", "b", "c"] else "nothing")
["a", "b", "c", "a", "b", "c"]
> data.mapcat(nil, (x) -> x)
nil
> data.mapcat("foo", (x) -> x)
ERROR:
code: ILLEGAL_ARGUMENT
message: map is not defined for type string
...
zip
(list xs, list ys) -> list
Returns a list of same length as xs
. Each index i
contains the value [xs[i], ys[i]]
.
Returns nil
if xs
or ys
are nil
.
> data.zip(["a", "b", "c"], [1, 2, 3])
[["a", 1], ["b", 2], ["c", 3]]
> data.zip([1, 2], [1, 2, 3])
[[1, 1], [2, 2]]
> data.zip([1, 2, 3], [1, 2])
[[1, 1], [2, 2], [3, nil]]
> data.zip([1, 2], nil)
nil
> data.zip(nil, [1, 2])
nil
zip_dict
(list keys, list values) -> dict
Returns a dict
with all keys from keys
. Each key contains the value values[i]
, where i
is the index of the key in keys
.
In case there are duplicate keys in keys
, the last index of a key provides the corresponding value.
Returns nil
if keys
or values
are nil
.
Throws an error if any key cannot be cast to string.
> data.zip_dict(["a", "b", "c"], [1, 2, 3])
{
:a 1,
:b 2,
:c 3
}
> data.zip_dict(["a", "b"], [1, 2, 3])
{
:a 1,
:b 2
}
> data.zip_dict(["a", "b", "c"], [1, 2])
{
:a 1,
:b 2,
:c nil
}
> data.zip_dict(["a", "b", "a", "b"], [1, 2, 3, 4])
{
:a 3,
:b 4
}
> data.zip_dict(["a", "b"], nil)
nil
> data.zip_dict(nil, [1, 2])
nil
index_by
(xs, function f) -> dict
Returns a dict
that contains all values from xs
. Each x
in xs
is indexed by key f(x)
.
If xs
is a list:
If f
accepts one argument, x
is passed.
If f
accepts two arguments, x
and its index are passed.
If xs
is a dict:
If f
accepts one argument, each entry’s value is passed.
If f
accepts two arguments, each entry’s value and key are passed.
The indexing function f
must return a string, or a value that can be cast to string.
In case f(x)
returns the same key for multiple x
, only one of such x
will be indexed in the returned dict.
In such cases it is undefined which x
is preserved in the returned dict.
In case f(x)
returns nil
the corresponding x
is omitted from the result.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if f
is nil
.
> data.index_by([{:id 'id_1', :name "Sherlock Holmes"}, {:id 'id_2', :name "Dr. Watson"}], (x) -> x[:id])
{
:id_1 {
:name "Sherlock Holmes",
:id "id_1"
},
:id_2 {
:name "Dr. Watson",
:id "id_2"
}
}
> data.index_by({:a1 1, :a2 2, :a3 3}, (x) -> "b"..x)
{
:b1 1,
:b2 2,
:b3 3
}
> data.index_by({:a1 1, :a2 2, :a3 3}, (x, k) -> "_" .. k)
{
:_a1 1,
:_a2 2,
:_a3 3
}
index_deep_by
(xs, function f) -> dict
Returns a nested dict
that contains all values from xs
. Each x
in xs
is indexed by a sequence of keys f(x)
.
If xs
is a list:
If f
accepts one argument, x
is passed.
If f
accepts two arguments, x
and its index are passed.
If xs
is a dict:
If f
accepts one argument, each entry’s value is passed.
If f
accepts two arguments, each entry’s value and key are passed.
The indexing function f
must return a list of strings representing a path of keys where item x
should be found.
In case f(x)
returns the same path of keys for multiple x
, only one of such x
will be indexed in the returned dict.
In such cases it is undefined which x
is preserved in the returned dict.
If f
returns paths p1 and p2, p2 is longer than p1, and p2 starts with p1, the behavior of index_deep_by
is undefined.
In case f(x)
returns nil
or an empty list, the corresponding x
is omitted from the result.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if f
is nil
.
> data.index_deep_by([{:l1 "a", :l2 "b"}, {:l1 "a", :l2 "c"}, {:l1 "b", :l2 "a"}], (x) -> [x[:l1], x[:l2]])
{
:a {
:b {:l1 "a", :l2 "b"},
:c {:l1 "a", :l2 "c"}
},
:b {
:a {:l1 "b", :l2 "a"}
}
}
group_by
(xs, function f) -> dict
Returns a dict
. Each x
of xs
is collected in a list located at the key given by f(x)
.
If xs
is a list:
If f
accepts one argument, x
is passed.
If f
accepts two arguments, x
and its index are passed.
If xs
is a dict:
If f
accepts one argument, each entry’s value is passed.
If f
accepts two arguments, each entry’s value and key are passed.
The indexing function f
must return a string representing the key to the list where item x
should be placed.
The order of items in collecting lists is undefined.
In case f(x)
returns nil
, the corresponding x
is omitted from the result.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if f
is nil
.
> data.group_by([0, 1, 2, 3, 4, 5], (x) -> if x % 2 == 0 then "even" else "odd")
{
:odd [1, 3, 5],
:even [0, 2, 4]
}
group_deep_by
(xs, function f) -> dict
Returns a nested dict
. Each x
of xs
is collected in a list located at the sequence of keys given by f(x)
.
If xs
is a list:
If f
accepts one argument, x
is passed.
If f
accepts two arguments, x
and its index are passed.
If xs
is a dict:
If f
accepts one argument, each entry’s value is passed.
If f
accepts two arguments, each entry’s value and key are passed.
The indexing function f
must return a list of strings representing a path of keys to the list where item x
should be placed.
The order of items in collecting lists is undefined.
If f
returns paths p1 and p2, p2 is longer than p1, and p2 starts with p1, the behavior of group_deep_by
is undefined.
In case f(x)
returns nil
or an empty list, the corresponding x
is omitted from the result.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if f
is nil
.
> data.group_deep_by([-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5], (x) -> [if x < 0 then "negative" else "positive", x % 2 == 0 then "even" else "odd"])
{
:positive {
:even [0, 2, 4],
:odd [1, 3, 5]
},
:negative {
:even [-2, -4],
:odd [-1, -3, -5]
}
}
interpose
(list xs, s) -> list
Returns a list
with all elements from xs
separated by s
.
Returns nil
if xs
is nil
.
> data.interpose([1, 2, 3, 4], 0)
[1, 0, 2, 0, 3, 0, 4]
> data.interpose([1], "foo")
[1]
> data.interpose([], "foo")
[]
> data.interpose(nil, "foo")
nil
reduce
(xs, init, function f) -> any
Expects xs
to be a list
or a dict
.
Sets the initial accumulator value to init
, iterates through all xs
, and calls f
for each x
.
If f
accepts two arguments, the current accumulator value and x
are passed.
If f
accepts three arguments, the current accumulator value, x
, and the index or key of x
are passed.
After each call the return value of f
becomes the new accumulator value.
Returns final accumulator value after iteration over xs
is completed.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if f
is nil
.
> data.reduce([1,2,3], 0, (a, x) -> a+x)
6
> data.reduce([], 0, (a, x) -> a+x)
0
> data.reduce(["a", "b", "c"], {}, (a, x, i) -> data.put(a, x, i))
{
:a 0,
:b 1,
:c 2
}
> data.reduce({:a 1, :b 2, :c 3}, 0, (a, x) -> a+x)
6
> data.reduce({}, 0, (a, x) -> a+x)
0
> data.reduce({:a "alpha", :b "beta", :c "gamma"}, {}, (a, x, k) -> data.put(a, x, k))
{
:gamma "c",
:beta "b",
:alpha "a"
}
> data.reduce(nil, 0, (a, x) -> x)
nil
> data.reduce("foo", 0, (a, x) -> a)
ERROR:
code: ILLEGAL_ARGUMENT
message: reduce is not defined for type string
...
reduce_until
(xs, init, function p, function f) -> any
Expects xs
to be a list
or a dict
.
Sets the initial accumulator value to init
, and iterates through all xs
.
For each x
, calls predicate function p
passing in the current accumulator value.
If the return value of p
casts to boolean true
, aborts iteration and returns the current
accumulator value immediately. Otherwise continues the reduction process by calling f
.
If f
accepts two arguments, the current accumulator value and x
are passed.
If f
accepts three arguments, the current accumulator value, x
, and the index or key of x
are passed.
After each call the return value of f
becomes the new accumulator value.
Returns final accumulator value after iteration over xs
is completed.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if p
is nil
or f
is nil
.
# sum up integers, until sum exceeds 10
> data.reduce_until([1,2,3,4,5,6,7,8], 0, (a) -> a > 10, (a, x) -> a+x)
15
# initial value is checked
> data.reduce_until([1, 2, 3], 0, (a) -> true, (a, x) -> a+x)
0
> data.reduce_until({:a "alpha", :b "beta", :c "gamma"}, {}, (a) -> data.size(a) == 2, (a, x, k) -> data.put(a, x, k))
{
:beta "b",
:alpha "a"
}
> data.reduce_until(nil, 0, (a) -> true, (a, x) -> x)
nil
> data.reduce_until("foo", 0, (a) -> true, (a, x) -> a)
ERROR:
code: ILLEGAL_ARGUMENT
message: reduce_until is not defined for type string
reduce_while
(xs, init, function p, function f) -> any
Expects xs
to be a list
or a dict
.
Sets the initial accumulator value to init
, and iterates through all xs
.
For each x
, calls predicate function p
passing in the current accumulator value.
If the return value of p
casts to boolean true
, continues the reduction process by calling f
.
Otherwise aborts iteration and returns the current accumulator value immediately.
If f
accepts two arguments, the current accumulator value and x
are passed.
If f
accepts three arguments, the current accumulator value, x
, and the index or key of x
are passed.
After each call the return value of f
becomes the new accumulator value.
Returns final accumulator value after iteration over xs
is completed.
Returns nil
if xs
is nil
.
Throws an error if xs
is neither a list
nor a dict
.
Throws an error if p
is nil
or f
is nil
.
# sum up integers, until sum exceeds 10
> data.reduce_while([1,2,3,4,5,6,7,8], 0, (a) -> a <= 10, (a, x) -> a+x)
15
# initial value is checked
> data.reduce_while([1, 2, 3], 0, (a) -> false, (a, x) -> a+x)
0
> data.reduce_while({:a "alpha", :b "beta", :c "gamma"}, {}, (a) -> data.size(a) < 2, (a, x, k) -> data.put(a, x, k))
{
:beta "b",
:alpha "a"
}
> data.reduce_while(nil, 0, (a) -> true, (a, x) -> x)
nil
> data.reduce_while("foo", 0, (a) -> true, (a, x) -> a)
ERROR:
code: ILLEGAL_ARGUMENT
message: reduce_while is not defined for type string
library time
The time library provides functions for processing datetime values.
epoch
datetime
The instant of time at 1970-01-01T00:00:00Z
of
(
long year=1970,
long month=1,
long day_of_month=1,
long hour=0,
long minute=0,
long second=0,
long nano_of_second=0,
string tz="UTC"
) -> datetime
Returns a datetime with components set to the given arguments.
If resulting datetime is in a DST gap, the datetime is adjusted forward by the length of the gap. If resulting datetime is in a DST overlap, the earlier valid offset is used.
Returns nil
if any argument is nil
.
> time.of()
1970-01-01T00:00:00Z@UTC
> time.of(2019, 04, 10, tz: "Europe/Berlin")
2019-04-10T00:00:00+02:00@Europe/Berlin
> time.of(2019, 04, 10, 16, 23, 11, 999000000, "America/New_York")
2019-04-10T16:23:11.999-04:00@America/New_York
# DST gap
> time.of(2019, 03, 31, 2, 30, tz: "Europe/Berlin")
2019-03-31T03:30:00+02:00@Europe/Berlin
> time.of(nil)
nil
at
(
datetime base,
long hour=0,
long minute=0,
long second=0,
long nano_of_second=0
) -> datetime
Returns datetime base with time components set to the given arguments.
If resulting datetime is in a DST gap, the datetime is adjusted forward by the length of the gap. If resulting datetime is in a DST overlap, the earlier valid offset is used.
Returns nil
if any argument is nil
.
> time.at(time.epoch, 23, 12, 10)
1970-01-01T23:12:10Z@UTC
> time.at(2019-04-10T00:00:00+02:00@Europe/Berlin, 6, 30)
2019-04-10T06:30:00+02:00@Europe/Berlin
# DST gap
> time.at(2019-03-31T00:00:00+01:00@Europe/Berlin, 2, 30)
2019-03-31T03:30:00+02:00@Europe/Berlin
> time.at(nil)
nil
seconds_between
(
datetime start_inclusive,
datetime end_exclusive
) -> long
Returns the number of full seconds between given datetimes.
Returns a negative number if start datetime is after end datetime.
Returns nil
if any argument is nil
.
> time.seconds_between(time.epoch, time.epoch)
0
> time.seconds_between(1970-01-01T00:00:00, 1970-01-01T00:00:01)
1
> time.seconds_between(1970-01-01T00:00:01, 1970-01-01T00:00:00)
-1
> time.seconds_between(time.epoch, 2018-01-01T00:00:00)
1514764800
> time.seconds_between(nil, nil)
nil
minutes_between
(
datetime start_inclusive,
datetime end_exclusive
) -> long
Returns the number of full minutes between given datetimes.
Returns a negative number if start datetime is after end datetime.
Returns nil
if any argument is nil
.
> time.minutes_between(time.epoch, time.epoch)
0
> time.minutes_between(1970-01-01T00:00:00, 1970-01-01T00:01:00)
1
> time.minutes_between(1970-01-01T00:01:00, 1970-01-01T00:00:00)
-1
> time.minutes_between(time.epoch, 2018-01-01T00:00:00)
25246080
> time.minutes_between(nil, nil)
nil
hours_between
(
datetime start_inclusive,
datetime end_exclusive
) -> long
Returns the number of full hours between given datetimes.
Returns a negative number if start datetime is after end datetime.
Returns nil
if any argument is nil
.
> time.hours_between(time.epoch, time.epoch)
0
> time.hours_between(1970-01-01T00:00:00, 1970-01-01T01:00:00)
1
> time.hours_between(1970-01-01T01:00:00, 1970-01-01T00:00:00)
-1
> time.hours_between(time.epoch, 2018-01-01T00:00:00)
420768
> time.hours_between(nil, nil)
nil
days_between
(
datetime start_inclusive,
datetime end_exclusive
) -> long
Returns the number of full days between given datetimes.
Returns a negative number if start datetime is after end datetime.
Returns nil
if any argument is nil
.
> time.days_between(time.epoch, time.epoch)
0
> time.days_between(1970-01-01T, 1970-01-02T)
1
> time.days_between(1970-01-02T, 1970-01-01T)
-1
> time.days_between(time.epoch, 2018-01-01T)
17532
> time.days_between(nil, nil)
nil
months_between
(
datetime start_inclusive,
datetime end_exclusive
) -> long
Returns the number of full months between given datetimes.
Returns a negative number if start datetime is after end datetime.
Returns nil
if any argument is nil
.
> time.months_between(time.epoch, time.epoch)
0
> time.months_between(1970-01-01T, 1970-02-01T)
1
> time.months_between(1970-02-01T, 1970-01-01T)
-1
> time.months_between(time.epoch, 2018-01-01T)
576
> time.months_between(nil, nil)
nil
years_between
(
datetime start_inclusive,
datetime end_exclusive
) -> long
Returns the number of full years between given datetimes.
Returns a negative number if start datetime is after end datetime.
Returns nil
if any argument is nil
.
> time.years_between(time.epoch, time.epoch)
0
> time.years_between(1970-01-01T, 1971-01-01T)
1
> time.years_between(1971-01-01T, 1970-01-01T)
-1
> time.years_between(time.epoch, 2018-01-01T)
48
> time.years_between(nil, nil)
nil
period_between
(
datetime start_inclusive,
datetime end_exclusive
) -> dict
Returns a dict with long values on keys :years
, :months
, and :days
, representing a calendar period between two datetimes.
The values are negative if start datetime is after end datetime.
Returns nil
if any argument is nil
.
> time.period_between(time.epoch, time.epoch)
{
:months 0,
:years 0,
:days 0
}
> time.period_between(1970-01-01T00:00:00, 1973-08-02T12:23:13)
{
:months 7,
:years 3,
:days 1
}
> time.period_between(1973-08-02T12:23:13, 1970-01-01T00:00:00)
{
:months -7,
:years -3,
:days -1
}
> time.period_between(nil, nil)
nil
duration_between
(
datetime start_inclusive,
datetime end_exclusive
) -> dict
Returns a dict with long values on keys :seconds
, and :nano_seconds
, representing a duration between two datetimes.
:seconds
are negative if start datetime is after end datetime.
:nano_seconds
is never negative and within the range of 0 - 999,999,999
.
A duration of -1
nanosecond is represented as -1
:seconds
and 999,999,999
:nanoseconds
.
Returns nil
if any argument is nil
.
> time.duration_between(time.epoch, time.epoch)
{
:nano_seconds 0,
:seconds 0
}
> time.duration_between(1970-01-01T00:00:00, 1970-01-01T00:00:00.000000001)
{
:nano_seconds 1,
:seconds 0
}
> time.duration_between(1970-01-01T00:00:00.000000001, 1970-01-01T00:00:00)
{
:nano_seconds 999999999,
:seconds -1
}
> time.duration_between(1970-01-01T00:00:00.00000233, 1973-08-02T12:23:13.928736)
{
:nano_seconds 928733670,
:seconds 113142193
}
> time.duration_between(nil, nil)
nil
add_period
(
datetime start,
long years=0,
long months=0,
long days=0
) -> datetime
Adds a calendar period to the given start datetime and returns the result.
Supply negative period numbers to effectively subtract a period.
Returns nil
if any argument is nil
.
> time.add_period(time.epoch, 0, 0, 1)
1970-01-02T00:00:00Z@UTC
> time.add_period(time.epoch, 0, 0, -1)
1969-12-31T00:00:00Z@UTC
> time.add_period(2017-05-24T, 1, 2, 3)
2018-07-27T00:00:00Z@UTC
> time.add_period(time.epoch, 2, 23, -98)
1973-08-25T00:00:00Z@UTC
> time.add_period(nil, nil, nil, nil)
nil
add_duration
(
datetime start,
long seconds=0,
long nano_of_second=0
) -> datetime
Adds a time duration to the given start datetime and returns the result.
Supply negative numbers to effectively subtract a duration.
Returns nil
if any argument is nil
.
> time.add_duration(time.epoch, 0, 1)
1970-01-01T00:00:00.000000001Z@UTC
> time.add_duration(time.epoch, 0, -1)
1969-12-31T23:59:59.999999999Z@UTC
> time.add_duration(2017-05-24T00:00:00Z, 3600)
2017-05-24T01:00:00Z@UTC
> time.add_duration(2017-05-24T00:00:00Z, -3600)
2017-05-23T23:00:00Z@UTC
> time.add_duration(nil, nil, nil)
nil
year
(datetime x) -> long
Returns the year component of given datetime x
.
Returns nil
if x
is nil
.
> time.year(time.epoch)
1970
> time.year(2017-02-21T)
2017
> time.year(nil)
nil
quarter
(datetime x) -> long
Returns the quarter for given datetime x
. Returns 1 for Jan-Mar, 2 for Apr-Jun, 3 for Jul-Sep, 4 for Oct-Dec.
Returns nil
if x
is nil
.
> time.week_of_year(2023-12-24)
4
> time.quarter(2017-02-21T)
1
> time.quarter(nil)
nil
month
(datetime x) -> long
Returns the month component of given datetime x
.
Returns nil
if x
is nil
.
> time.month(time.epoch)
1
> time.month(2017-02-21T)
2
> time.month(nil)
nil
day_of_month
(datetime x) -> long
Returns the day of month component of given datetime x
.
Returns nil
if x
is nil
.
> time.day_of_month(time.epoch)
1
> time.day_of_month(2017-02-21T)
21
> time.day_of_month(nil)
nil
day_of_year
(datetime x) -> long
Returns the day of year of given datetime x
.
Returns nil
if x
is nil
.
> time.day_of_year(time.epoch)
1
> time.day_of_year(2017-02-21T)
52
> time.day_of_year(nil)
nil
day_of_week
(datetime x) -> long
Returns the day of week of given datetime x
.
The returned number represents a day of week as per the following mapping.
| Nr | Day of week |
|---|---|
| 1 | Monday |
| 2 | Tuesday |
| 3 | Wednesday |
| 4 | Thursday |
| 5 | Friday |
| 6 | Saturday |
| 7 | Sunday |
Returns nil
if x
is nil
.
> time.day_of_week(time.epoch)
4
> time.day_of_week(2017-05-24T)
3
> time.day_of_week(nil)
nil
hour
(datetime x) -> long
Returns the hour of given datetime x
.
Returns nil
if x
is nil
.
> time.hour(time.epoch)
0
> time.hour(2017-02-21T23:00:00)
23
> time.hour(nil)
nil
minute
(datetime x) -> long
Returns the minute of given datetime x
.
Returns nil
if x
is nil
.
> time.minute(time.epoch)
0
> time.minute(2017-02-21T00:59:00)
59
> time.minute(nil)
nil
second
(datetime x) -> long
Returns the second of given datetime x
.
Returns nil
if x
is nil
.
> time.second(time.epoch)
0
> time.second(2017-02-21T00:00:12)
12
> time.second(nil)
nil
nano_of_second
(datetime x) -> long
Returns the nanoseconds of given datetime x
.
Returns nil
if x
is nil
.
> time.nano_of_second(time.epoch)
0
> time.nano_of_second(2017-02-21T00:00:00.123456789)
123456789
> time.nano_of_second(2017-02-21T00:00:00.01)
10000000
> time.nano_of_second(nil)
nil
week_of_year
(datetime x) -> long
Returns the week of year for given datetime x
. The ISO-8601 definition of weeks is used, where a week starts on Monday and the first week of a year has a minimum of 4 days.
Returns nil
if x
is nil
.
> time.week_of_year(time.epoch)
1
> time.week_of_year(2010-01-01T)
53
> time.week_of_year(2011-01-01T)
52
> time.week_of_year(2012-01-01T)
52
> time.week_of_year(2013-01-01T)
1
> time.week_of_year(2017-02-21T)
8
> time.week_of_year(nil)
nil
offset_seconds
(datetime x) -> long
Returns the number of seconds in the offset from UTC for given datetime x
.
Returns nil
if x
is nil
.
> time.offset_seconds(time.epoch)
0
> time.offset_seconds(2010-01-01T00:00:00.00+02:00)
7200
> time.offset_seconds(2011-01-01T00:00:00.00-03:00)
-10800
> time.offset_seconds(nil)
nil
zone
(datetime x) -> string
Returns the time zone for given datetime x
.
Returns nil
if x
is nil
.
> time.zone(time.epoch)
"UTC"
> time.zone(2010-01-01T00:00:00.00+02:00)
"UTC+02:00"
> time.zone(2010-01-01T00:00:00.00+01:00@Europe/Berlin)
"Europe/Berlin"
> time.zone(nil)
nil
end_of_month
(datetime x, long add_months=0) -> datetime
Returns the datetime representing the end of month of a given datetime x
. The time component of x
is preserved
in the result.
If add_months
is non-zero, the given amount of months is added to x
and the end of month of the resulting
datetime is returned.
Returns nil
if x
is nil
.
Returns nil
if add_months
is nil
.
> time.end_of_month(time.epoch)
1970-01-31T00:00:00Z@UTC
> time.end_of_month(2020-02-21T)
2020-02-29T00:00:00Z@UTC
> time.end_of_month(2019-06-02T, -1)
2019-05-31T00:00:00Z@UTC
> time.end_of_month(2019-02-02T12:23:34@Europe/Berlin, 12)
2020-02-29T12:23:34+01:00@Europe/Berlin
> time.day_of_month(nil)
nil
with_year
(datetime x, long year) -> datetime
Returns the datetime x
with the year field set to year
. If the day-of-month is invalid for the
resulting datetime, it will be changed to the last valid day of the month.
Returns nil
if any argument is nil
.
Throws an error if year is out of bounds of -999999999 - 999999999.
> time.with_year(time.epoch, 2007)
2007-01-01T00:00:00Z@UTC
> time.with_year(2016-02-29T, 2019)
2019-02-28T00:00:00Z@UTC
> time.with_year(time.epoch, nil)
nil
> time.with_year(nil, 2017)
nil
> time.with_year(time.epoch,<PHONE_NUMBER>)
ERROR:
code: ILLEGAL_ARGUMENT
message: Invalid value for Year (valid values -999999999 - 999999999):<PHONE_NUMBER>
with_month
(datetime x, long month) -> datetime
Returns the datetime x
with the month field set to month
.
If the day-of-month is invalid for the resulting datetime, it will be changed to the last valid day of the month.
Returns nil
if any argument is nil
.
Throws an error if no datetime can be constructed with given month.
> time.with_month(time.epoch, 6)
1970-06-01T00:00:00Z@UTC
> time.with_month(2016-03-31T, 2)
2016-02-29T00:00:00Z@UTC
> time.with_month(time.epoch, nil)
nil
> time.with_month(nil, 6)
nil
> time.with_month(time.epoch, 13)
ERROR:
code: ILLEGAL_ARGUMENT
message: Invalid value for MonthOfYear (valid values 1 - 12): 13
with_day_of_month
(datetime x, long day_of_month) -> datetime
Returns the datetime x
with the day_of_month field set to day_of_month
.
Returns nil
if any argument is nil
.
Throws an error if no datetime can be constructed with given day_of_month
.
> time.with_day_of_month(time.epoch, 23)
1970-01-23T00:00:00Z@UTC
> time.with_day_of_month(2016-02-01T, 29)
2016-02-29T00:00:00Z@UTC
> time.with_day_of_month(2010-02-01T, 29)
ERROR:
code: ILLEGAL_ARGUMENT
message: Invalid date 'February 29' as '2010' is not a leap year
...
> time.with_day_of_month(time.epoch, nil)
nil
> time.with_day_of_month(nil, 23)
nil
> time.with_day_of_month(time.epoch, 33)
ERROR:
code: ILLEGAL_ARGUMENT
message: Invalid value for DayOfMonth (valid values 1 - 28/31): 33
with_hour
(datetime x, long hour) -> datetime
Returns the datetime x
with the hour field set to hour
.
If resulting datetime is in a DST gap, the datetime is adjusted forward by the length of the gap.
Returns nil
if any argument is nil
.
Throws an error if no datetime can be constructed with given hour
.
> time.with_hour(time.epoch, 4)
1970-01-01T04:00:00Z@UTC
# 2:30 is in a 1h DST gap, it technically did not exist
> time.with_hour(2019-03-31T01:30:00+01:00@Europe/Berlin, 2)
2019-03-31T03:30:00+02:00@Europe/Berlin
> time.with_hour(time.epoch, nil)
nil
> time.with_hour(nil, 4)
nil
> time.with_hour(time.epoch, 25)
ERROR:
code: ILLEGAL_ARGUMENT
message: Invalid value for HourOfDay (valid values 0 - 23): 25
with_minute
(datetime x, long minute) -> datetime
Returns the datetime x
with the minute field set to minute
.
If resulting datetime is in a DST gap, the datetime is adjusted forward by the length of the gap.
Returns nil
if any argument is nil
.
Throws an error if no datetime can be constructed with given minute
.
> time.with_minute(time.epoch, 42)
1970-01-01T00:42:00Z@UTC
> time.with_minute(time.epoch, nil)
nil
> time.with_minute(nil, 42)
nil
> time.with_minute(time.epoch, 78)
ERROR:
code: ILLEGAL_ARGUMENT
message: Invalid value for MinuteOfHour (valid values 0 - 59): 78
with_second
(datetime x, long second) -> datetime
Returns the datetime x
with the second field set to second
.
If resulting datetime is in a DST gap, the datetime is adjusted forward by the length of the gap.
Returns nil
if any argument is nil
.
Throws an error if no datetime can be constructed with given second
.
> time.with_second(time.epoch, 42)
1970-01-01T00:00:42Z@UTC
> time.with_second(time.epoch, nil)
nil
> time.with_second(nil, 42)
nil
> time.with_second(time.epoch, 78)
ERROR:
code: ILLEGAL_ARGUMENT
message: Invalid value for SecondOfMinute (valid values 0 - 59): 78
with_nano_of_second
(datetime x, long nano_of_second) -> datetime
Returns the datetime x
with the nano_of_second field set to nano_of_second
.
If resulting datetime is in a DST gap, the datetime is adjusted forward by the length of the gap.
Returns nil
if any argument is nil
.
Throws an error if no datetime can be constructed with given nano_of_second
.
> time.with_nano_of_second(time.epoch, 123456789)
1970-01-01T00:00:00.123456789Z@UTC
> time.with_nano_of_second(time.epoch, nil)
nil
> time.with_nano_of_second(nil, 123456789)
nil
> time.with_nano_of_second(time.epoch,<PHONE_NUMBER>)
ERROR:
code: ILLEGAL_ARGUMENT
message: Invalid value for NanoOfSecond (valid values 0 - 999999999):<PHONE_NUMBER>
with_zone
(datetime x, string tz) -> datetime
Returns the datetime x
with the time zone field set to tz
.
If resulting datetime is in a DST gap, the datetime is adjusted forward by the length of the gap.
If resulting datetime is in a DST overlap, the earlier valid offset is used.
Returns nil
if any argument is nil
.
Throws an error if no datetime can be constructed with given tz
.
> time.with_zone(time.epoch, "Europe/Berlin")
1970-01-01T00:00:00+01:00@Europe/Berlin
> time.with_zone(time.epoch, "GMT+08:00")
1970-01-01T00:00:00+08:00@`GMT+08:00`
> time.with_zone(time.epoch, 'America/New_York')
1970-01-01T00:00:00-05:00@America/New_York
> time.with_zone(time.epoch, nil)
nil
> time.with_zone(nil, "Europe/Berlin")
nil
> time.with_zone(time.epoch, "---")
ERROR:
code: ILLEGAL_ARGUMENT
message: unknown time zone id: ---
same_instant_at_zone
(datetime x, string tz) -> datetime
Returns a datetime representing the same instant as x
in time zone tz
.
Returns nil
if any argument is nil
.
Throws an error if no datetime can be constructed with given tz
.
> time.same_instant_at_zone(time.epoch, "Europe/Berlin")
1970-01-01T01:00:00+01:00@Europe/Berlin
> time.same_instant_at_zone(time.epoch, "GMT+08:00")
1970-01-01T08:00:00+08:00@`GMT+08:00`
# the instant in time is the same
> time.compare(1970-01-01T01:00:00+01:00@Europe/Berlin, 1970-01-01T08:00:00+08:00@`GMT+08:00`)
0
> time.same_instant_at_zone(time.epoch, nil)
nil
> time.same_instant_at_zone(nil, "Europe/Berlin")
nil
> time.same_instant_at_zone(time.epoch, "---")
ERROR:
code: ILLEGAL_ARGUMENT
message: unknown time zone id: ---
unix_timestamp
(datetime x) -> long
Returns a long representing the number of seconds since epoch for the given x
.
Returns nil
if x
is nil
.
> time.unix_timestamp(time.epoch)
0
> time.unix_timestamp(2017-06-08T14:59:55Z@UTC)
1496933995
> time.unix_timestamp(1922-07-26T09:00:05Z@UTC)
-1496933995
unix_timestamp_ms
(datetime x) -> long
Returns a long representing the number of milliseconds since epoch for the given x
.
Returns nil
if x
is nil
.
> time.unix_timestamp_ms(time.epoch)
0
> time.unix_timestamp_ms(2017-06-08T14:59:55.123Z@UTC)
1496933995123
> time.unix_timestamp_ms(1922-07-26T09:00:04.877Z@UTC)
-1496933995123
of_unix_timestamp
(long s) -> datetime
Returns a datetime representing epoch + s
seconds in time zone UTC
.
Returns nil
if s
is nil
.
> time.of_unix_timestamp(0)
1970-01-01T00:00:00Z@UTC
> time.of_unix_timestamp(1496933995)
2017-06-08T14:59:55Z@UTC
> time.of_unix_timestamp(-1496933995)
1922-07-26T09:00:05Z@UTC
of_unix_timestamp_ms
(long ms) -> datetime
Returns a datetime representing epoch + ms
milliseconds in time zone UTC
.
Returns nil
if ms
is nil
.
> time.of_unix_timestamp_ms(0)
1970-01-01T00:00:00Z@UTC
> time.of_unix_timestamp_ms(1496933995763)
2017-06-08T14:59:55.763Z@UTC
> time.of_unix_timestamp_ms(-1496933995763)
1922-07-26T09:00:04.237Z@UTC
compare
(datetime a, datetime b) -> long
Compares two datetimes a
and b
.
Returns -1 if a
precedes b
.
Returns 1 if b
precedes a
.
Returns 0 if a
and b
describe the same instant in time.
Assumes nil
to precede any non-nil datetime.
> time.compare(time.epoch, time.epoch)
0
> time.compare(time.epoch, 2017-05-24T)
-1
> time.compare(2017-05-24T, time.epoch)
1
> time.compare(2017-05-24T00:00:00, 2017-05-24T02:00:00+02:00)
0
> data.sort([2017-05-24T00:00:00, 2017-05-25T00:00:00, nil, 2017-05-24T00:01:00, 2017-05-24T02:00:00], time.compare)
[nil, 2017-05-24T00:00:00Z@UTC, 2017-05-24T00:01:00Z@UTC, 2017-05-24T02:00:00Z@UTC, 2017-05-25T00:00:00Z@UTC]
formatter
(
string pattern="uuuu-MM-dd'T'HH:mm:ssZZZZZ'@`'VV'`'",
string lang="en-US"
) -> function
Returns a function f
that accepts a single datetime parameter x
, and returns a string representation of x
using the
supplied pattern and language tag.
f
returns nil
if nil
is passed as an argument.
Throws an error if any argument is nil
.
Throws an error if pattern
is not a valid pattern for the DateTimeFormatter of the Java language.
> f: time.formatter("d MMM uuuu")
function
> f(time.epoch)
"1 Jan 1970"
> f: time.formatter("d MMM uuuu", "fr")
function
> f(time.epoch)
"1 janv. 1970"
> f: time.formatter("cccc, d MMMM uuuu")
function
> f(time.epoch)
"Thursday, 1 January 1970"
> f: time.formatter("cccc, d MMMM uuuu", "de")
function
> f(time.epoch)
"Donnerstag, 1 Januar 1970"
parser
(
string pattern="uuuu-MM-dd'T'HH:mm:ss[ZZZZZ]['@`'VV'`']",
string lang="en-US",
string default_tz="UTC",
boolean lenient=false
) -> function
Returns a function f
that accepts a single string paramter x
and returns a parsed datetime value as specified by the supplied
pattern and language tag.
f
returns nil
when nil
is passed as an argument.
If lenient
is false, f
throws an error on strings that parse to invalid dates.
If lenient
is true, the parser will attempt to correct invalid datetime values. A date of January 32nd will parse as February 1st, for example.
The default time zone is used unless the pattern parses both a time component and a time zone in which case the parsed values are used.
Throws an error if any argument is nil
.
Throws an error if pattern
is not a valid pattern for the DateTimeFormatter of the Java language.
> f: time.parser("uuuu-MM-dd'T'HH:mm:ss[ZZZZZ]['@`'VV'`']")
function
> f(nil)
nil
> f("2017-04-23T21:43:11")
2017-04-23T21:43:11Z@UTC
> f("2017-04-23T21:43:11@`Europe/Berlin`")
2017-04-23T21:43:11+02:00@Europe/Berlin
# patterns specifies mandatory @ sign and backticks before timezone
> f("2017-04-23T21:43:11 Europe/Berlin")
ERROR:
code: ILLEGAL_ARGUMENT
message: Text '2017-04-23T21:43:11 Europe/Berlin' could not be parsed, unparsed text found at index 19
# strict parser
> f: time.parser('uuuu-MM-dd')
function
# there is no march 32nd
> f("2015-03-32")
ERROR:
code: ILLEGAL_ARGUMENT
message: Text '2015-03-32' could not be parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 32
# lenient parser
> f: time.parser('uuuu-MM-dd', lenient: true)
function
# lenient parser interprets march 32nd as april 1st
> f("2015-03-32")
2015-04-01T00:00:00Z@UTC
# parses local times setting the default time zone
> f: time.parser('uuuu-MM-dd[ HH:mm:ss]', default_tz: 'America/Chicago')
function
> f("2017-06-22 12:34:11")
2017-06-22T12:34:11-05:00@America/Chicago
> f("2017-06-22")
2017-06-22T00:00:00-05:00@America/Chicago
zones
() -> list
Returns a list of all known time zone ids.
> time.zones()
["Africa/Abidjan", "Africa/Accra", "Africa/Addis_Ababa", ...]
# get all Europe/x time zones
> data.filter(time.zones(), (z) -> strings.split(z, "/")[0] == "Europe")
["Europe/Amsterdam", "Europe/Andorra", "Europe/Astrakhan", "Europe/Athens", ...]
# get all US/x time zones
> data.filter(time.zones(), (z) -> strings.split(z, "/")[0] == "US")
["US/Alaska", "US/Aleutian", "US/Arizona", "US/Central", "US/East-Indiana", "US/Eastern", ...]
library math
The math library contains basic mathematical functions.
abs
(x) ->
If x
is a double
, returns the absolute value of x
as a double.
If x
is NaN
, the result is NaN
.
If x
is -Infinity
the result is Infinity
.
If x
is a long
, returns the absolute value of x
as a long.
If x
is a long, and is equal to math.min_long
, the absolute value cannot be represented as a long, and an error is thrown.
If x
is a decimal
, returns the absolute value of x
as a decimal.
If x
is nil
, returns nil
.
Throws an error if x
is not numeric and not nil
.
> math.abs(100)
100
> math.abs(-100)
100
> math.abs(-2.0)
2.0
> math.abs(-1.000d)
1.000d
> math.abs(-Infinity)
Infinity
> math.abs(NaN)
NaN
> math.abs(math.min_long)
ERROR:
code: NUMBER_OUT_OF_BOUNDS
message: cannot represent magnitude as long
> math.abs(math.min_long as double)
9.223372036854776E18
> math.abs(nil)
nil
> math.abs("hello")
ERROR:
code: ILLEGAL_ARGUMENT
message: cannot determine magnitude of type string
rand
(any seed) -> double
Returns a pseudo-random double between 0.0
inclusive and 1.0
exclusive, based on given seed
.
This function deterministically returns the same number for the same seed
.
nil
is a valid seed
value.
> dice_roll: (any seed) -> (math.rand(seed) *6 +1) as long
function
> dice_roll("hello")
3
> dice_roll("hi")
6
> \e
dice_rolls: (long count, any seed) ->
fun.iterate(
1, count, # loop 1-count times
{:seed [seed], :nums []}, # initial state
(state, i) ->
# accumulate seed list and number list and return new state
let {
r: math.rand(state[:seed]);
n: (r*6+1) as long;
}
{
:seed [...state[:seed], r*i],
:nums [...state[:nums], n]
}
)[:nums]
\e
function
> dice_rolls(3, "foo")
[5, 1, 5]
> dice_rolls(10, "foo")
[5, 1, 5, 3, 3, 5, 6, 6, 5, 3]
> dice_rolls(3, "bar")
[6, 1, 1]
> dice_rolls(10, "bar")
[6, 1, 1, 3, 6, 4, 3, 5, 6, 5]
> math.rand(nil)
0.730967787376657
rands
(long count, any seed) -> list
Returns a list of length count
of pseudo-random double values between 0.0
inclusive and 1.0
exclusive, based on given seed
.
This function deterministically returns the same list for the same seed
.
nil
is a valid seed
value.
Returns nil
if count
is nil
.
Throws an error if count
is negative.
> math.rands(2, "foo")
[0.7636542620472306, 0.4845448486565105]
> math.rands(2, "bar")
[0.8603985347346733, 0.7525012276982017]
> math.rands(3, nil)
[0.730967787376657, 0.24053641567148587, 0.6374174253501083]
> math.rands(-7)
ERROR:
code: ILLEGAL_ARGUMENT
message: count cannot be negative, found: -7
inc
(any x) -> any
Increments x
by one.
If x
is a double, returns x+1.0
If x
is a long, returns x+1
If x
is a decimal, returns x+1d
\
Does not guard against overflow of long values.
If x
is nil
, returns nil
.
Throws an error if x
is not numeric.
> math.inc(2.0)
3.0
> math.inc(-2.0)
-1.0
> math.inc(1)
2
> math.inc(4.1234d)
5.1234d
> math.inc(math.max_long)
-9223372036854775808 # overflow to math.min_long
> math.inc(nil)
nil
> math.inc([])
ERROR:
code: ILLEGAL_ARGUMENT
message: cannot increment type list
dec
(any x) -> any
Decrements x
by one.
If x
is a double, returns x-1.0
If x
is a long, returns x-1
If x
is a decimal, returns x-1d
\
Does not guard against underflow of long values.
If x
is nil
, returns nil
.
Throws an error if x
is not numeric.
> math.dec(2.0)
1.0
> math.dec(-2.0)
-3.0
> math.dec(-2.1d)
-3.1d
> math.dec(1)
0
> math.dec(math.min_long)
9223372036854775807 # overflow to math.max_long
> math.dec(nil)
nil
> math.dec([])
ERROR:
code: ILLEGAL_ARGUMENT
message: cannot decrement type list
compare
(a, b) -> long
Compares numbers a and b according to their numeric order.
Returns -1 if a < b.
Returns 1 if a > b.
Returns 0 if a == b.
The order reflected by this function sorts these values in order: nil
, NaN
, -Infinity
, finite numeric values, and Infinity
.
Throws an error if a
or b
are not nil
, and not numeric.
> math.compare(1, 1)
0
> math.compare(nil, 7)
-1
> math.compare(7.0, 2)
1
> data.sort([4, 3, 2.5d, 1, 0.2, nil, NaN, -Infinity, Infinity], math.compare)
[nil, NaN, -Infinity, 0.2, 1, 2.5d, 3, 4, Infinity]
min
(list xs) -> any
Given a list of numeric xs
, returns the smallest x
.\
Returns nil
if xs
is nil
, xs
is empty, or any x
in xs
is nil
or NaN
.
Throws an error if any x
is anything other than a numeric value or nil
.
> math.min([1,2,3])
1
> math.min([1.0, 2d, -3.0])
-3.0
> math.min([1, nil])
nil
> math.min(nil)
nil
> math.min(["foo"])
ERROR:
code: ILLEGAL_ARGUMENT
message: cannot compare type string
max
(list xs) -> any
Given a list of numeric xs
, returns the largest x
.
Returns nil
if xs
is nil
, xs
is empty, or any x
in xs
is nil
or NaN
.
Throws an error if any x
is anything other than a numeric value or nil
.
> math.max([1,2,3])
3
> math.max([1.0, 2.0, -3d])
2.0
> math.max([1, nil])
nil
> math.max(nil)
nil
> math.max(["foo"])
ERROR:
code: ILLEGAL_ARGUMENT
message: cannot compare type string
round
(double x) -> long
Given a double x
, returns x
rounded to the closest long value. Ties are rounded up.
Returns 0
if x
is NaN
.
Returns math.min_long
if x
is -Infinity
or less than or equal to math.min_long
.
Returns math.max_long
if x
is Infinity
or greater than or equal to math.max_long
.
Returns nil
if x
is nil
.
> math.round(2.3)
2
> math.round(2.5)
3
> math.round(-2.3)
-2
> math.round(-2.5)
-2
> math.round(nil)
nil
ceil
(double x) -> double
Given a double x
, returns the smallest double value greater than or equal to x
that is a mathematical integer.
Returns -Infinity
if x
is -Infinity
.
Returns Infinity
if x
is Infinity
.
Returns NaN
if x
is NaN
.
Returns nil
if x
is nil
.
> math.ceil(2.3)
3.0
> math.ceil(-2.3)
-2.0
> math.ceil(nil)
nil
floor
(double x) -> double
Given a double x
, returns the largest double value smaller than or equal to x
that is a mathematical integer.
Returns -Infinity
if x
is -Infinity
.
Returns Infinity
if x
is Infinity
.
Returns NaN
if x
is NaN
.
Returns nil
if x
is nil
.
> math.floor(2.3)
2.0
> math.floor(-2.3)
-3.0
> math.floor(nil)
nil
NaN?
(any x) -> boolean
Given a value x
, returns true
if x
is NaN, returns false
otherwise.
> math.NaN?(2.3)
false
> math.NaN?(NaN)
true
> math.NaN?(nil)
false
finite?
(any x) -> boolean
Returns false
if x
is nil
, NaN
, -Infinity
, or Infinity
.
Returns true
if x
is a finite numeric value.
Throws an error if x
is not of type long
, double
, or decimal
.
> math.finite?(2.3)
true
> math.finite?(NaN)
false
> math.finite?(Infinity)
false
sqrt
(double x) -> double
Given a double x
, returns the square root of x
.
Returns NaN
if x
is negative.
Returns Infinity
if x
is Infinity
.
Returns nil
if x
is nil
.
> math.sqrt(9.0)
3.0
> math.sqrt(-9.0)
NaN
> math.sqrt(nil)
nil
factorial
(long x) -> decimal
if x
is non-negative, returns the factorial of x
.
If x
is nil
, returns nil
.
Throws an error if x
is negative.
> math.factorial(0)
1d
> math.factorial(1)
1d
> math.factorial(2)
2d
> math.factorial(25)
15511210043330985984000000d
> math.factorial(nil)
nil
> math.factorial(-1)
ERROR:
code: ILLEGAL_ARGUMENT
sin
(double x) -> double
Returns the trigonometric sine of angle x
given in radians.
Returns NaN
if x
is an Infinity
or NaN
.
Returns nil
if x
is nil
.
> math.sin(0)
0.0
> math.sin(math.pi/2)
1.0
> math.sin(1)
0.8414709848078965
cos
(double x) -> double
Returns the trigonometric cosine of angle x
given in radians.
Returns NaN
if x
is an Infinity
or NaN
.
Returns nil
if x
is nil
.
> math.cos(0)
1.0
> math.cos(math.pi)
-1.0
> math.cos(math.pi*2)
1.0
> math.cos(1)
0.5403023058681398
tan
(double x) -> double
Returns the trigonometric tangent of angle x
given in radians.
Returns NaN
if x
is an Infinity
or NaN
.
Returns nil
if x
is nil
.
> math.tan(0)
0.0
> math.tan(1)
1.5574077246549023
> math.tan(math.pi/4)
0.9999999999999999
asin
(double x) -> double
Returns the arc sine of x
in the range of -pi/2 throuh pi/2.
Returns NaN
if x
is NaN
or its absolute value is greater than 1.
Returns nil
if x
is nil
.
> math.asin(0)
0.0
> math.asin(0.5)
0.5235987755982989
> math.asin(1)
1.5707963267948966
acos
(double x) -> double
Returns the arc cosine of x
in the range of 0.0 throuh pi.
Returns NaN
if x
is NaN
or its absolute value is greater than 1.
Returns nil
if x
is nil
.
> math.acos(0)
1.5707963267948966
> math.acos(0.5)
1.0471975511965979
> math.acos(1)
0.0
> math.acos(-1)
3.141592653589793
atan
(double x) -> double
Returns the arc tangent of x
in the range of -pi/2 through pi/2.
Returns NaN
if x
is NaN
.
Returns nil
if x
is nil
.
> math.atan(0)
0.0
> math.atan(-1)
-0.7853981633974483
> math.atan(1)
0.7853981633974483
log
(double x) -> double
Returns the natural logarithm (base e) of x
.
Returns NaN
if x
is NaN
or less than 0
.
Returns -Infinity
if x
is 0
Returns Infinity
if x
is Infinity
Returns nil
if x
is nil
.
> math.log(0)
-Infinity
> math.log(1)
0.0
> math.log(math.e**2)
2.0
log10
(double x) -> double
Returns the base 10 logarithm of x
.
Returns NaN
if x
is NaN
or less than 0
.
Returns -Infinity
if x
is 0
Returns Infinity
if x
is Infinity
Returns nil
if x
is nil
.
> math.log10(0)
-Infinity
> math.log10(1)
0.0
> math.log10(100)
2.0
bit_count
(long x) -> long
Given a long x
, returns the number of bits set to 1 in the binary two’s complement representation of x
.
Returns nil
if x
is nil
.
> math.bit_count(1) # 1
1
> math.bit_count(2) # 10
1
> math.bit_count(3) # 11
2
> math.bit_count(nil)
nil
formatter
(
string pattern='0.##',
dict decimal_symbols=nil,
string rounding_mode="half_even",
boolean always_show_decimal_separator=false
) -> function
Returns a function f
that accepts a single numeric parameter x
, and returns a string representation of x
using the
supplied pattern,
decimal_symbols,
rounding mode, and
always_show_decimal_separator flag.
If decimal_symbols
is nil
(the default), ’en-US’ decimal symbols are used.
rounding_mode
is provided as a case-insensitive name of one of the rounding modes defined by the
Java language.
f
returns nil
if passed nil
as an argument.
f
throws an error if x
is not a numeric value.
Throws an error if pattern
is not a valid pattern for the DecimalFormat of the Java language.
Throws an error if decimal_symbols
is invalid.
Throws an error if rounding_mode
is nil
.
Throws an error if always_show_decimal_separator
is nil
.
> f: math.formatter()
function
> f(100)
"100"
> f(100.233)
"100.23"
> f: math.formatter('0.00', locale.decimal_symbols('fr'), 'half_even')
function
> f(100)
"100,00"
> f(100.233)
"100,23"
> f(20332.039)
"20332,04"
> f: math.formatter('#,##0.##', locale.decimal_symbols('hi-IN'))
function
std.tf> f(648722)
"६४८,७२२"
parser
(
string pattern='0.##',
dict decimal_symbols=nil,
boolean lenient=false,
boolean parse_decimal=false
) -> function
Returns a function f
that accepts a single string parameter x
and returns a parsed numeric value as specified by the supplied
pattern and decimal_symbols.
Uses en-US
decimal symbols if decimal_symbols
is nil
.
If lenient
is false
then x
must parse as a number in its entirety. Partial matches throw an error.
If lenient
is true
then partial matches of x
return the number that results from parsing the partial match.
If parse_decimal
is false, f
returns a long
or double
value.
If parse_decimal
is true, f
returns a decimal
value.
f
returns nil
if x
is nil
.
Throws an error if pattern
is not a valid pattern for the DecimalFormat of the Java language.
Throws an error if decimal_symbols
is invalid.
Throws an error if lenient
is nil
.
Throws an error if parse_decimal
is nil
.
> f: math.parser()
> f("203.23")
203.23
> f("203.23kg")
ERROR:
code: ILLEGAL_ARGUMENT
message: Partial match not allowed. Parsing ended at index: 6
# lenient parser
> f: math.parser('0.##', lenient: true)
function
> f("203.23kg")
203.23
# localized parser
> f: math.parser('#,##0.##', locale.decimal_symbols('hi-IN'))
function
> f("१०३")
103
# decimal parser
> f: math.parser('0.##', parse_decimal: true)
function
> f("203.23")
203.23d
e
The double value that is closer than any other to e
, the base of the natural logarithms.
pi
The double value that is closer than any other to pi
, the ratio of the circumference of a circle to its diameter.
min_long
The smallest representable long value: -9223372036854775808
.
max_long
The largest representable long value:<PHONE_NUMBER>854775807
.
library decimals
The decimals library contains utility functions for working with decimal numbers.
ulp
(decimal x) -> decimal
Returns the unit in the last place, of given decimal x
.
An ulp of a decimal is the positive distance between this value and the decimal next larger in magnitude with the same scale.
Returns nil
if x
is nil
.
> decimals.ulp(0.5d)
0.1d
> decimals.ulp(1.000d)
0.001d
> decimals.ulp(-1000d)
1d
> decimals.ulp(nil)
nil
scale
(decimal x) -> long
Returns the scale of given decimal x
.
A decimal number is internally represented as a mathematical integer x 10^(-scale).
A positive scale therefore indicates the number of fractional digits.
A negative scale represents a decimal that is stored in terms of 10, 100, 1000, etc. times some integer value, effectively dropping precision of trailing digits.
Returns nil
if x
is nil
.
# no fractional digits
> decimals.scale(0d)
0
# two fractional digits
> decimals.scale(0.00d)
2
# two fractional digits
> decimals.scale(0.75d)
2
# value 100 with -2 scale
> decimals.scale(1e+2d)
-2
with_scale
(
decimal x,
long scale,
string rounding_mode='half_up'
) -> decimal
Returns a decimal of the same value as x
with given scale
.
The given rounding mode is used when digits must be dropped to adapt the given scale.
Returns nil
if x
is nil
.
Throws an error if scale
or rounding_mode
are nil
.
> decimals.with_scale(0d, 3)
0.000d
> decimals.with_scale(5d, 2)
5.00d
> decimals.with_scale(1.29d, 1)
1.3d
> decimals.with_scale(1.29d, 1, 'down')
1.2d
# set negative scale -2, effectively storing the number at multiples of 100
> decimals.with_scale(1299d, -2)
1.3E+3d
> decimals.with_scale(1299d, -2, 'down')
1.2E+3d
round
(
decimal x,
long digits,
string rounding_mode='half_up'
) -> decimal
Returns a decimal of x
rounded to the given number of non-zero digits using the given rounding mode.
This function is useful to get a number with a relevant number of significant digits when dealing with numbers which contain many digits.
If you wish to round to a fixed number of decimal places or digits, use with_scale.
Returns nil
if x
is nil
.
If digits
is 0
, x
is returned.
Throws an error if digits
or rounding_mode
are nil
.
Throws an error if digits
is negative.
> decimals.round(0.0001234, 2)
0.00012d
> decimals.round(0.01234d, 2)
0.012d
> decimals.round(1.01234d, 2)
1.0d
> decimals.round(1999d, 2)
2.0E+3d
> decimals.round(1999, 3, 'down')
1.99E+3d
plain
(decimal x) -> string
Returns a plain string representation of the decimal, not using exponent notation.
Returns nil
if x
is nil
.
> decimals.plain(1d)
"1"
> decimals.plain(1.00d)
"1.00"
> decimals.plain(1e+6d)
"1000000"
> decimals.plain(1e-5d)
"0.00001"
strip_trailing_zeros
(decimal x) -> decimal
A decimal number is internally represented as a mathematical integer x 10^(-scale).
Returns a decimal numerically equal to x
in which scale and the integer part has
been adjusted to not store any trailing zeros in the integer part.
Returns nil
if x
is nil
.
> decimals.strip_trailing_zeros(1.00d)
1d
> decimals.strip_trailing_zeros(1.10d)
1.1d
> decimals.strip_trailing_zeros(100d)
1E+2d
> decimals.strip_trailing_zeros(110d)
1.1E+2d
divide
(
decimal x,
decimal y,
long scale,
string rounding_mode='half_up'
) -> decimal
Returns the result of x
divided by y
with given scale
and rounding mode.
If scale
is nil
, the scale of x
is used.
Returns nil
if x
or y
are nil
.
Throws an error if rounding_mode
is nil
.
Throws an error if y
is zero.
> decimals.divide(1d, 3d, 2)
0.33d
> decimals.divide(1d, 3d, 10)
0.3333333333d
> decimals.divide(1d, 3d, 2, 'up')
0.34d
# scale=nil means result uses scale of x
> decimals.divide(1.00000d, 3d)
0.33333d
# negative scale division
> decimals.divide(10_000d, 3d, -2)
3.3E+3d
# negative scale division rounded up
> decimals.divide(10_000d, 3d, -2, 'up')
3.4E+3d
divide_integral
(decimal x, decimal y) -> decimal
Returns the integer part of x
divided by y
. Any fractional digits are not included in the result.
The preferred scale of the result is scale(x) - scale(y)
, but the scale will be expanded to accommodate
additional digits, if necessary.
Returns nil
if x
or y
are nil
.
Throws an error if y
is zero.
> decimals.divide_integral(1d, 3d)
0d
> decimals.divide_integral(100d, 3d)
33d
> decimals.divide_integral(100d, -3d)
-33d
# scale of result is scale(x) - scale(y)
> decimals.divide_integral(10.54321d, 0.5d)
21.0000d
# scale of result is scale(x) - scale(y)
> decimals.divide_integral(10.54321d, 1E+1d)
1.000000d
from_double_exact
(double x) -> decimal
Floating point doubles encode approximations of fractional numbers.
This function returns the exact mathematical value of the given double as a decimal.
Returns nil
if x
is nil
.
> decimals.from_double_exact(1.0)
1d
> decimals.from_double_exact(2.6)
2.600000000000000088817841970012523233890533447265625d
> decimals.from_double_exact(0.1)
0.1000000000000000055511151231257827021181583404541015625d
> decimals.from_double_exact(nil)
nil
library fun
The function library contains utility functions to call functions using certain patterns or conditions. Functions in this library provide functionality similar to control-flow features in other languages.
times
(long n, any x, function f) -> any
Calls f
n
times with one argument. The first call of f
receives x
as argument.
Subsequent calls to f
receive as argument the result of the previous call.
Returns the result of the last call to f
, or x
if n
is 0
.
Returns nil
if n
is nil
.
Throws an error if n
is negative or f
is nil
.
> double_up: (x) -> 2*x
function
> fun.times(10, 1, double_up)
1024
Example: computing Fibonacci numbers
# helper: given fibonacci number n and n+1, compute fibonacci number n+1 and n+2
> next_fib_pair: (p) -> if p == [0, 0] then [0, 1] else [p[1], p[0]+p[1]]
function
# compute nth fibonacci number
> fib: (n) -> fun.times(n, [0, 0], next_fib_pair)[1]
function
> fib(10)
55
> data.map([1,2,3,4,5,6,7,8,9,10], fib)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
until
(function p, any x, function f) -> any
Calls f
repeatedly with one argument. The first call of f
receives x
as argument.
Subsequent calls to f
receive as argument the result of the previous call.
Before each call to f
, the argument is tested by predicate function p
.
If p
returns a value that casts to boolean true
, execution completes and the tested argument is returned.
Returns the first argument for which p
returns a value that casts to boolean true
.
Throws an error if p
is nil
or f
is nil
.
# keep doubling up 1 until the result exceeds 60,000
> fun.until((x) -> x>60000, 1, (x) -> x*2)
65536
# Generate natural numbers, until their sum exceeds 100.
# The data structure is a dict containing the list of
# numbers at key :nums and their sum at key :sum.
> \e
next: (x) ->
let {
n: data.size(x[:nums])+1;
}
{
:nums [...x[:nums], n],
:sum x[:sum]+n
}
\e
function
> fun.until((x) -> x[:sum] > 100, {:nums [], :sum 0}, next)
{
:sum 105,
:nums [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
}
while
(function p, any x, function f) -> any
Calls f
repeatedly with one argument. The first call of f
receives x
as argument.
Subsequent calls to f
receive as argument the result of the previous call.
Before each call to f
, the argument is tested by predicate function p
.
If p
returns a value that does not cast to boolean true
, execution completes and the tested argument is returned.
Returns the first argument for which p
returns a value that does not cast to boolean true
.
Throws an error if p
is nil
or f
is nil
.
# keep doubling up 1 while the result is smaller than 60,000
> fun.while((x) -> x<60000, 1, (x) -> x*2)
65536
# Generate natural numbers, while their sum is smaller than 100.
# The data structure is a dict containing the list of
# numbers at key :nums and their sum at key :sum.
> \e
next: (x) ->
let {
n: data.size(x[:nums])+1;
}
{
:nums [...x[:nums], n],
:sum x[:sum]+n
}
\e
function
> fun.while((x) -> x[:sum] < 100, {:nums [], :sum 0}, next)
{
:sum 105,
:nums [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
}
iterate
(long start, long end, any x, function f) -> any
Calls f
repeatedly with two arguments. The first call of f
receives x
as first argument.
Subsequent calls to f
receive as first argument the result of the previous call.
The second argument is an index starting at start
and ending inclusively at end
.
Returns the result of the last call to f
.
Returns x
if end
< start
.
Returns nil
if start
is nil
or end
is nil
.
Throws an error if f
is nil
.
# add natural numbers 1 to 10
> fun.iterate(1, 10, 0, (sum, i) -> sum+i)
55
thread
(any state, list fs) -> any
Calls functions from given fs
in sequence, passing state
as the argument to the first function,
and the result of the previous call to subsequent calls. Returns result of final call.
Returns state
if fs
is empty.
Throws an error if fs
is nil.
> \e
rev_str: (str) -> fun.thread(
str,
[
(x) -> strings.chars(x), # split to chars
(x) -> data.reverse(x), # reverse order
(x) -> strings.join(x) # and re-join
]
)
\e
function
> rev_str("dlrow olleh")
"hello world"
chain
(list fs) -> function
Given a list of functions fs
, returns a composite function that calls all functions in fs
in order.
fun.chain([f, g])(x) == g(f(x))
Returns core.id
identity function if fs
is empty.
Throws an error if fs
is nil
.
> f: fun.chain([(x) -> x+10, (x) -> x*2]) # add 10, then double result
function
> f(1) # (1+10)*2
22
compose
(list fs) -> function
Given a list of functions fs
, returns a composite function that calls all functions in fs
in reverse order, consistent
with conventional mathematical notation.
fun.compose([f, g])(x) == f(g(x))
Returns core.id
identity function if fs
is empty.
Throws an error if fs
is nil
.
> f: fun.compose([(x) -> x+10, (x) -> x*2]) # double result, then add 10
function
> f(1) # (1*2)+10
12
signature
(function f) -> dict
Returns a dict
describing the signature of f
.
The following keys are present:
| key | value |
|---|---|
| return_type | string indicating the declared return type |
| parameters | list indicating the declared parameters |
Each parameter in the parameters list is a dict of the form:
| key | value |
|---|---|
| index | long indicating the index of the parameter |
| declared_type | string indicating the declared type |
| name | string indicating the name of the parameter |
| default_value | the default value of the parameter |
Returns nil
if f
is nil
.
> fun.signature(strings.replace)
{
:return_type "string",
:parameters [{
:name "x",
:index 0,
:default_value nil,
:declared_type "string"
}, {
:name "search",
:index 1,
:default_value nil,
:declared_type "string"
}, {
:name "replace",
:index 2,
:default_value nil,
:declared_type "string"
}]
}
> fun.signature(fun.signature)
{
:return_type "dict",
:parameters [{
:name "f",
:index 0,
:default_value nil,
:declared_type "function"
}]
}
library locale
The locale library provides information about available localization conventions. Localization conventions are relevant in the context of number and date formatting as well as string sorting.
languages
(lang='en-US') -> dict
Returns a dict of language tags (BCP 47) to human readable names of all available languages. The human readable names are given in the language tag passed as the locale parameter, if available.
Returns en-US
display names if lang
is nil
or unknown.
# list available languages with french display names
> locale.languages('fr')
{
:`en-IE` "anglais (Irlande)",
:`ar-AE` "arabe (Emirats Arabes Unis)",
:`ar-JO` "arabe (Jordanie)",
:de "allemand",
:hi "hindi",
:no "norvégien",
:`be-BY` "biélorusse (Biélo-Russie)",
:`es-PR` "espagnol (Porto Rico)",
:`zh-HK` "chinois (Hong-Kong)",
:`en-CA` "anglais (Canada)",
:`zh-TW` "chinois (Taiwan)",
...
}
decimal_symbols
(lang='en-US') -> dict
Returns a dict containing the decimal symbols used for number representation in given language.
The dict contains the following keys:
| Key | Value |
|---|---|
| decimal_separator | The character representing a decimal separator. |
| grouping_separator | The character representing a grouping separator. |
| exponent_separator | The string used to separate the mantissa from the exponent in scientific notation. |
| zero_digit | The character representing the zero digit. The subsequent 9 character values are treated as digits 1-9. |
| minus_sign | The character representing the minus sign. |
| infinity | The string representing infinity. |
| NaN | The string representing NaN (Not a Number) values. |
Returns en-US
decimal symbols if lang
is nil
.
> locale.decimal_symbols()
{
:infinity "∞",
:grouping_separator ",",
:minus_sign "-",
:exponent_separator "E",
:zero_digit "0",
:decimal_separator ".",
:NaN "�"
}
> locale.decimal_symbols('fr')
{
:infinity "∞",
:grouping_separator " ",
:minus_sign "-",
:exponent_separator "E",
:zero_digit "0",
:decimal_separator ",",
:NaN "�"
}
> locale.decimal_symbols('hi-IN')
{
:infinity "∞",
:grouping_separator ",",
:minus_sign "-",
:exponent_separator "E",
:zero_digit "०",
:decimal_separator ".",
:NaN "�"
}
library bin
The bin library provides functions that operate on binary data.
concat
(list xs) -> binary
Expects a list of binary values. Returns a binary that contains all bytes of all binaries in given order.
Returns nil
if xs
is nil
.
Returns nil
if any element of xs
is nil
.
Throws an error if any element of xs
is not a binary.
> bin.concat([0b00, 0b01])
0b0001
> bin.concat([nil, 0b01])
nil
size
(binary x) -> long
Returns the number of bytes in x
.
Returns nil
if x
is nil
.
> bin.size(0b)
0
> bin.size(0b01020304)
4
> bin.size(nil)
nil
byte_at
(binary x, long i) -> long
Returns the byte at byte offset i
in binary x
as a long between 0 and 255.
Returns nil
if any argument is nil
.
Returns nil
if i<0
or i>=size(x)
.
> bin.byte_at(0b01020304, 3)
4
> bin.byte_at(0bFF, 0)
255
> bin.byte_at(0b, 10)
nil
word_at
(binary x, long i, boolean big_endian=false) -> long
Returns the word (16-bit integer value) at byte offset i
in binary x
as a long between 0 and 65535.
Interprets bytes as most significant last. If big_endian
is true
, interprets bytes as most significant first.
Returns nil
if any argument is nil
.
Returns nil
if i<0
or i+1>=size(x)
.
> bin.word_at(0b0100, 0)
1
> bin.word_at(0b0100, 0, true)
256
> bin.word_at(0b000F, 0)
3840
> bin.word_at(0b000F, 0, true)
15
> bin.word_at(0bFF, 0)
nil
dword_at
(binary x, long i, boolean big_endian=false) -> long
Returns the double-word (32-bit integer value) at byte offset i
in binary x
as a long between 0 and<PHONE_NUMBER>.
Interprets bytes as most significant last. If big_endian
is true
, interprets bytes as most significant first.
Returns nil
if any argument is nil
.
Returns nil
if i<0
or i+3>=size(x)
.
> bin.dword_at(0b01000000, 0)
1
> bin.dword_at(0b01000000, 0, true)
16777216
> bin.dword_at(0bFF, 0)
nil
long_at
(binary x, long i, boolean big_endian=false) -> long
Returns the long (64-bit integer value) at byte offset i
in binary x
as a signed long.
Interprets bytes as most significant last. If big_endian
is true
, interprets bytes as most significant first.
Returns nil
if any argument is nil
.
Returns nil
if i<0
or i+7>=size(x)
.
> bin.long_at(0b0100000000000000, 0)
1
> bin.long_at(0b0100000000000000, 0, true)
72057594037927936
> bin.long_at(0bFFFFFFFFFFFFFFFF, 0)
-1
> bin.long_at(0bFF, 0)
nil
of_byte
(long x, boolean signed=false) -> binary
Returns the binary representation of the given byte.
If signed is true
, x
must be a value between -128
and 127
.
If signed is false
, x
must be a value between 0
and 255
.
Returns nil
if x
is nil
.
Throws an error if signed
is nil
.
> bin.of_byte(64)
0b40
> bin.of_byte(192)
0bc0
> bin.of_byte(255)
0bff
> bin.of_byte(-1, true)
0bff
> bin.of_byte(-1, false)
ERROR:
code: ILLEGAL_ARGUMENT
message: unsigned byte value out of range: -1
of_word
(long x, boolean signed=false, boolean big_endian=false) -> binary
Returns the binary representation of the given 2-byte word.
If signed
is true
, x
must be a value between −32768
and 32767
.
If signed
is false
, x
must be a value between 0
and 65535
.
If big_endian
is true
, the returned binary starts with the most significant byte.
If big_endian
is false
, the returned binary starts with the least significant byte.
Returns nil
if x
is nil
.
Throws an error if signed
is nil
.
Throws an error if big_endian
is nil
.
> bin.of_word(192)
0bc000
> bin.of_word(192, big_endian: true)
0b00c0
> bin.of_word(65535)
0bffff
> bin.of_word(-32768, signed: true)
0b0080
> bin.of_word(-32768, signed: true, big_endian: true)
0b8000
> bin.of_word(65535, signed: true)
ERROR:
code: ILLEGAL_ARGUMENT
message: signed word value out of range: 65535
of_dword
(long x, boolean signed=false, boolean big_endian=false) -> binary
Returns the binary representation of the given 4-byte dword.
If signed
is true
, x
must be a value between −2147483648
and<PHONE_NUMBER>
.
If signed
is false
, x
must be a value between 0
and<PHONE_NUMBER>
.
If big_endian
is true
, the returned binary starts with the most significant byte.
If big_endian
is false
, the returned binary starts with the least significant byte.
Returns nil
if x
is nil
.
Throws an error if signed
is nil
.
Throws an error if big_endian
is nil
.
> bin.of_dword(255)
0bff000000
> bin.of_dword(255, big_endian: true)
0b000000ff
> bin.of_dword(-128, signed: true)
0b80ffffff
> bin.of_dword(-128, signed: true, big_endian: true)
0bffffff80
> bin.of_dword(4294967295)
0bffffffff
> bin.of_dword(4294967295, signed: true)
ERROR:
code: ILLEGAL_ARGUMENT
message: signed dword value out of range:<PHONE_NUMBER>
of_long
(long x, boolean big_endian=false) -> binary
Returns the 64-bit binary representation of the given long value.
If big_endian
is true
, the returned binary starts with the most significant byte.
If big_endian
is false
, the returned binary starts with the least significant byte.
Returns nil
if x
is nil
.
Throws an error if big_endian
is nil
.
> bin.of_long(255)
0bff00000000000000
> bin.of_long(255, big_endian: true)
0b00000000000000ff
> bin.of_long(9223372036854775807)
0bffffffffffffff7f
> bin.of_long(-1)
0bffffffffffffffff
of_float
(double x, boolean big_endian=false) -> binary
Returns the 32-bit binary representation of the float closest to the given double value.
If big_endian
is true
, the returned binary starts with the most significant byte.
If big_endian
is false
, the returned binary starts with the least significant byte.
Returns nil
if x
is nil
.
Throws an error if big_endian
is nil
.
> bin.of_float(0)
0b00000000
> bin.of_float(1)
0b0000803f
> bin.of_float(1, big_endian: true)
0b3f800000
> bin.of_float(NaN)
0b0000c07f
> bin.of_float(math.pi)
0bdb0f4940
of_double
(double x, boolean big_endian=false) -> binary
Returns the 64-bit binary representation of the given double value.
If big_endian
is true
, the returned binary starts with the most significant byte.
If big_endian
is false
, the returned binary starts with the least significant byte.
Returns nil
if x
is nil
.
Throws an error if big_endian
is nil
.
> bin.of_double(0.0)
0b0000000000000000
> bin.of_double(1.0)
0b000000000000f03f
> bin.of_double(1.0, big_endian: true)
0b3ff0000000000000
> bin.of_double(NaN)
0b000000000000f87f
> bin.of_double(math.pi)
0b182d4454fb210940
float_at
(binary x, long i, boolean big_endian=false) -> double
Returns the float (32-bit floating point value) at byte offset i
in binary x
as a double.
Interprets bytes as most significant last. If big_endian
is true
, interprets bytes as most significant first.
Returns nil
if any argument is nil
.
Returns nil
if i<0
or i+3>=size(x)
.
> bin.float_at(0b00000000, 0)
0.0
> bin.float_at(0b0000803f, 0)
1.0
> bin.float_at(0b0000803f, 0, true)
4.600602988224807E-41
> bin.float_at(0b40490fdb, 0, true)
3.1415927410125732
> bin.float_at(0b0000807f, 0)
Infinity
> bin.float_at(0b0100C0ff, 0)
NaN
> bin.float_at(0bFF, 0)
nil
double_at
(binary x, long i, boolean big_endian=false) -> double
Returns the double (64-bit floating point value) at byte offset i
in binary x
as a double.
Interprets bytes as most significant last. If big_endian
is true
, interprets bytes as most significant first.
Returns nil
if any argument is nil
.
Returns nil
if i<0
or i+7>=size(x)
.
> bin.double_at(0b0000000000000000, 0)
0.0
> bin.double_at(0b000000000000f03f, 0)
1.0
> bin.double_at(0bc000000000000000, 0, true)
-2.0
> bin.double_at(0b000000000000f07f, 0)
Infinity
> bin.double_at(0b000000000000f0ff, 0)
-Infinity
> bin.double_at(0b010000000000f07f, 0)
NaN
> bin.double_at(0b400921fb54442d18, 0, true)
3.141592653589793
> bin.double_at(0bFF, 0)
nil
slice
(binary x, long start=0, long end=nil) -> list
Returns a range of bytes from x
starting at byte offset start
inclusively, and extending to byte offset end
exclusively.
If end
is nil
, the range extends to the end of x
.
Returns a zero length binary if start
is greater than the size of x
.
Returns a zero length binary if start >= end
.
Returns nil
if x
is nil
.
Throws an error if start
is nil
or start < 0
.
> bin.slice(0b00010203, 2)
0b0203
> bin.slice(0b00010203040506, 1, 4)
0b010203
> bin.slice(0b, 10, 20)
0b
> bin.slice(0b0001020304, 1, 1)
0b
> bin.slice(nil)
nil
to_hex
(binary x) -> string
Returns a hexadecimal string representing the binary value x
.
Returns nil
if x
is nil
.
> bin.to_hex(0b010A0B04)
"010a0b04"
> bin.to_hex(0b)
""
> bin.to_hex(nil)
nil
from_hex
(string x) -> binary
Returns the binary value represented by given hexadecimal string x
.
Returns nil
if x
is nil
.
Throws an error if x
contains non-hexadecimal characters.
> bin.from_hex("010a0b04")
0b010A0B04
> bin.from_hex("")
0b
> bin.from_hex(nil)
nil
base64_encode
(binary x, string variant='basic') -> string
Returns the base64 string representation of given binary data x
.
If variant
is equal to 'basic'
, the standard base64 alphabet of RFC 2045 and RFC 4648 is used.
If variant
is equal to 'url'
, the “URL and Filename safe” base64 alphabet of RFC 4648 is used.
If variant
is equal to 'mime'
, the standard base64 alphabet of RFC 2045 is used.
In addition the encoded output is represented in lines of no more than 76 characters each
and uses a carriage return \r
followed immediately by a linefeed \n
as the line separator.
Returns nil
if x
is nil
or variant
is nil
.
Throws an error if variant
is not nil
and not equal to any supported variant.
> bin.base64_encode(0b00010203)
"AAECAw=="
> bin.base64_encode(strings.to_bytes("Hello World"))
"SGVsbG8gV29ybGQ="
> bin.base64_encode(nil)
nil
base64_decode
(string x, string variant='basic') -> binary
Returns the bytes encoded by given base64 string x
.
If variant
is equal to 'basic'
, the standard base64 alphabet of RFC 2045 and RFC 4648 is used.
If variant
is equal to 'url'
, the “URL and Filename safe” base64 alphabet of RFC 4648 is used.
If variant
is equal to 'mime'
, the standard base64 alphabet of RFC 2045 is used. Any characters
not found in the standard alphabet table are ignored.
Returns nil
if x
is nil
or variant
is nil
.
Throws an error if variant
is not nil
and not equal to any supported variant.
Throws an error if variant
is basic
or url
and any non-alphabet characters are encountered.
> bin.base64_decode("AA==")
0b00
> bin.base64_decode("SGVsbG8gV29ybGQh")
0b48656c6c6f20576f726c6421
> strings.from_bytes(bin.base64_decode("SGVsbG8gV29ybGQh"))
"Hello World!"
> bin.base64_decode(nil)
nil