函数与算符#
函数是表达式的一种。Cozo 中除了读取当前时间的函数和以 rand_
开头的函数之外,其它所有的函数都是纯函数:给出同样的参数,其值相同。
不是函数#
首先我们来介绍一些不是函数的构造。函数的求值规则是先对其参数求值,然后将参数的值传入函数的正文,得到一个值作为结果。以下这些构造不是函数,因为其不遵守这个规则。
首先,以下构造不返回值:
var = expr
显性地将var
与expr
归一。注意与算符形式的函数expr1 == expr2
的区别。not clause
将原子clause
否定。注意与算符形式的函数!expr
以及函数negate(expr)
的区别。clause1 or clause2
将两个原子进行析取。注意与函数or(expr1, expr2)
的区别。clause1 and clause2
将两个原子进行合取。注意与函数and(expr1, expr2)
的区别。clause1, clause2
将两个原子进行合取。
以上最后三项中, or
的优先级最高, and
次之, ,
最低。 and
与 ,
的唯一区别就是他们的优先级。
以下构造返回值,但是不是函数:
if(a, b, c)
首先对a
求值,若为真,则对b
求值并返回其结果,否则对c
求值并返回其结果。a
的求值结果必须是布尔值。if(a, b)
与if(a, b, null)
等价。cond(a1, b1, a2, b2, ...)
首先对a1
求值,若其值为真,则对b1
求值并返回其结果,否则对a2
及b2
进行相同操作,直到有结果返回。此构造必须给出偶数个参数,且所有的a
都必须求值为布尔值。若所有的a
的值都为假,则返回空值。若想返回非空的默认值,则可以在最后一对参数的第一个中使用真值作为参数。
函数的算符表达#
为了书写简便,一些函数有算符表示。以下是二元算符:
a && b
等价于and(a, b)
a || b
等价于or(a, b)
a ^ b
等价于pow(a, b)
a ++ b
等价于concat(a, b)
a + b
等价于add(a, b)
a - b
等价于sub(a, b)
a * b
等价于mul(a, b)
a / b
等价于div(a, b)
a % b
等价于mod(a, b)
a >= b
等价于ge(a, b)
a <= b
等价于le(a, b)
a > b
等价于gt(a, b)
a < b
等价于le(a, b)
a == b
等价于eq(a, b)
a != b
等价于neq(a, b)
a ~ b
等价于coalesce(a, b)
二元算符的优先级如下(以行记,前面的行中所包括的算符优先级高,后面的低;同一行中所有算符有相机相同):
~
^
*
,/
+
,-
,++
%
==
,!=
>=
,<=
,>
,<
&&
||
除 ^
之外,所有二元算符都向左关联,即 a / b / c
。
(a / b) / c
。 ^
则向右关联: a ^ b ^ c
等价于 a ^ (b ^ c)
。
一元算符如下:
-a
等价于minus(a)
!a
等价于negate(a)
在需要改变算符顺序时,可以使用括号。括号优先级最高,其次是一元算符,最后是二元算符。
相等与比较#
- eq(x, y)#
相等。算符形式为
x == y
。两个参数如果类型不同,则结果为假值。
- neq(x, y)#
不等。算符形式为
x != y
。两个参数如果类型不同,则结果为真值。
- gt(x, y)#
大于。算符形式为
x > y
。
- ge(x, y)#
大于等于。算符形式为
x >= y
。
- lt(x, y)#
小于。算符形式为
x < y
。
- le(x, y)#
小于等于。算符形式为
x <= y
。
备注
大小比较的两个参数必须隶属于同类型,否则会报错。在 Cozo 中,整数与浮点数的运行时类型相同,都是 Number
。
- max(x, ...)#
返回参数中的最大值。所有参数都必须是数字。
- min(x, ...)#
返回参数中的最小值。所有参数都必须是数字。
布尔函数#
- and(...)#
接受任意个参数的合取。二元形式等价于
x && y
。
- or(...)#
接受任意个参数的析取。二元形式等价于
x || y
。
- negate(x)#
否定。等价于
!x
。
- assert(x, ...)#
若
x
为真则返回真,否则抛出异常。给出多个参数时其它参数会包含在异常中,可以作为错误信息。
数学函数#
- add(...)#
多参数形式的加法。二元形式等价于
x + y
。
- sub(x, y)#
减法,等价于
x - y
。
- mul(...)#
多参数形式的乘法。二元形式等价于
x * y
。
- div(x, y)#
除法,等价于
x / y
。
- minus(x)#
求负,等价于
-x
。
- pow(x, y)#
x
的y
次方。等价于x ^ y
。返回浮点数,即使参数都是整数。
- mod(x, y)#
x
对y
求模(余数)。参数可以是浮点数。返回的值的符号与x
相同。等价于x % y
。
- abs(x)#
绝对值。
- signum(x)#
返回
1
、0
或-1
中与所传参数符号一样的数,比如signum(to_float('NEG_INFINITY')) == -1
,signum(0.0) == 0
,但是signum(-0.0) == -1
。如果参数为NAN
则返回NAN
。
- floor(x)#
向下求整。
- ceil(x)#
向上求整。
- round(x)#
四舍五入。当遇到点五时,取离 0 远的值,如
round(0.5) == 1.0
,round(-0.5) == -1.0
,round(1.4) == 1.0
。
- exp(x)#
指数函数,以自然对数 e 为底。
- exp2(x)#
指数函数,以 2 为底。即使参数是整数也返回浮点数。
- ln(x)#
对数函数,以自然对数为底。
- log2(x)#
对数函数,以 2 为底。
- log10(x)#
对数函数,以 10 为底。
- sin(x)#
正弦函数。
- cos(x)#
余弦函数。
- tan(x)#
正切函数。
- asin(x)#
正弦函数的反函数。
- acos(x)#
余弦函数的反函数。
- atan(x)#
正切函数的反函数。
- atan2(x, y)#
正切函数的反函数,同时传入两个参数,对这两个参数的比做反正切,并使用这两个参数的符号来决定返回值的象限。
- sinh(x)#
双曲正弦函数。
- cosh(x)#
双曲余弦函数。
- tanh(x)#
双曲正切函数。
- asinh(x)#
双曲正弦函数的反函数。
- acosh(x)#
双曲余弦函数的反函数。
- atanh(x)#
双曲正切函数的反函数。
- deg_to_rad(x)#
将角度转换为弧度。
- rad_to_deg(x)#
将弧度转换为角度。
- haversine(a_lat, a_lon, b_lat, b_lon)#
给出球面上两点的两对经纬度,使用 半正矢公式 来计算他们之间的夹角。经纬度都以弧度给出。由于地图上的经纬度通常以角度给出,下一个函数更常用一些。
- haversine_deg_input(a_lat, a_lon, b_lat, b_lon)#
与上面的函数的唯一区别是经纬度参数以角度而不是弧度给出。返回的值仍然是弧度而不是角度。
计算球面表面两点的球面距离时,将返回值乘以球的半径。比如地球的半径为
6371
公里,或3959
英里,或3440
海里。备注
由于地球并不是精确的球体,所以用此函数来计算距离时会有一定的误差,误差在百分之一之内。
字符串函数#
- length(str)#
返回字符串中含有的 Unicode 字符的数量。参数也可以是数组。
警告
length(str)
返回的不是字符串的字节长度,且两个等价的 Unicode 字符串可能规范化形式不同,而导致它们的长度不同。遇到这种情况时建议使用先对字符串使用unicode_normalize
函数来保证统一的规范化形式,然后再使用length
函数。
- concat(x, ...)#
串联字符串。二元形式等价于
x ++ y
。参数也可以都是数组。
- str_includes(x, y)#
如果字符串
x
包含 字符串y
的内容,则返回真,否则返回假。
- lowercase(x)#
将字符串转换为小写。支持 Unicode。
- uppercase(x)#
将字符串转换为大写。支持 Unicode。
- trim(x)#
删除字符串两头的空白字符。空白字符由 Unicode 标准定义。
- trim_start(x)#
删除字符串开头的空白字符。空白字符由 Unicode 标准定义。
- trim_end(x)#
删除字符串结尾的空白字符。空白字符由 Unicode 标准定义。
- starts_with(x, y)#
检查字符串
x
是否以y
为前缀。小技巧
使用
starts_with(var, str)
而不是等价的正则表达式可以帮助系统更好的优化查询:在一定情况下系统可以使用范围扫描而不是全局扫描。
- ends_with(x, y)#
检查字符串
x
是否以y
结尾。
- unicode_normalize(str, norm)#
对字符串
str
进行 Unicode 规范化。规范化种类norm
可以是'nfc'
、'nfd'
、'nfkc'
或'nfkd'
。
- chars(str)#
返回字符串中所含的 Unicode 字符。
- from_substrings(list)#
将一个字符串的数组组合成一个字符串。可以说是
chars
的逆函数。警告
由于 Unicode 的复杂性,Cozo 中的字符串不能以整数作为索引来查询特定位置的字符。如果查询时需要此功能,则需要先使用
chars
将其转化为数组。
数组函数#
- list(x, ...)#
将参数组成一个数组。
list(1, 2, 3)
等价于[1, 2, 3]
。
- is_in(el, list)#
测试元素是否在数组中。
- first(l)#
提取数组中的第一个元素。空数组返回空值。
- last(l)#
提取数组中的最后一个元素。空数组返回空值。
- get(l, n)#
返回数组中索引为
n
的元素,索引为整数,从 0 开始。若索引在范围之外则报错。
- maybe_get(l, n)#
返回数组中索引为
n
的元素,索引为整数,从 0 开始。若索引在范围之外则返回空值。
- length(list)#
返回数组的长度。也可以对字节数组及字符串使用。
- slice(l, start, end)#
从索引值
start
开始(含)到索引值end
为止(不含),取参数数组的子数组。索引值可以为负数,意义为从数组结尾开始计算的索引。例:slice([1, 2, 3, 4], 1, 3) == [2, 3]
、slice([1, 2, 3, 4], 1, -1) == [2, 3]
。
- concat(x, ...)#
将参数数组组成一个数组。二元形式等价于
x ++ y
。参数也可以是字符串。
- prepend(l, x)#
将元素
x
插入l
的最前端。
- append(l, x)#
将元素
x
插入l
的最后端。
- reverse(l)#
倒转数组。
- sorted(l)#
对数组进行排序,返回排序后的结果。
- chunks(l, n)#
将数组切为长度为
n
的多个数组,最后一个数组可能长度不够,例:chunks([1, 2, 3, 4, 5], 2) == [[1, 2], [3, 4], [5]]
。
- chunks_exact(l, n)#
将数组切为长度为
n
的多个数组,如果最后一个数组长度不够则舍弃之,例:chunks([1, 2, 3, 4, 5], 2) == [[1, 2], [3, 4]]
。
- windows(l, n)#
返回数组中长度为
n
的滑动窗口,例:windows([1, 2, 3, 4, 5], 3) == [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
。
- union(x, y, ...)#
返回给定参数(每个参数都代表一个集合)的联合。
- intersection(x, y, ...)#
返回给定参数(每个参数都代表一个集合)的交叉。
- difference(x, y, ...)#
返回第一个参数对其它参数(每个参数都代表一个集合)的差异。
二进制函数#
- length(bytes)#
返回字节数组的长度。也接受字符串及数组为参数。
- bit_and(x, y)#
返回两个字节数组比特级别的与。两个字节数组长度必须一致。
- bit_or(x, y)#
返回两个字节数组比特级别的或。两个字节数组长度必须一致。
- bit_not(x)#
返回字节数组比特级别的非。
- bit_xor(x, y)#
返回两个字节数组比特级别的排他或。两个字节数组长度必须一致。
- pack_bits([...])#
将一个包含布尔值的数组转换为一个字节数组。若参数中的数组长度不能被 8 整除,则以假值补足再转换。
- unpack_bits(x)#
将字节数组转换为布尔值的数组。
- encode_base64(b)#
将字节数组使用 Base64 编码为字符串。
备注
对列进行类型转化时,若列的类型为字节数组,则会自动套用此函数。
- decode_base64(str)#
尝试将字节使用 Base64 编码解码为字节数组。
类型检查与转换函数#
- coalesce(x, ...)#
聚凝算符,即返回第一个非空的值。若所有值都为空则返回空。二元形式等价于
x ~ y
。
- to_string(x)#
将参数转换为字符串。如参数本身就是字符串,则不做变更,否则使用 JSON 的字符串表示形式。
- to_float(x)#
将参数转换为浮点数。不管参数是什么,此函数都不会抛出异常,当无法转换时会返回特殊的浮点数
NAN
。以下是一些可转换的特殊字符串:INF
转换为正无穷大;NEG_INF
转换为负无穷大;NAN
转换为NAN
(两个NAN
不相等:若要检查值是否为NAN
,需要使用is_nan
函数);PI
转换为圆周率(3.14159…);E
转换为自然对数的底(欧拉常数之一,2.71828…)。
空值与假值转换为
0.0
,真值转换为1.0
。
- to_int(x)#
将参数转换为整数。当参数为有效性时,提取有效性中的整数时间戳。
- to_unity(x)#
将参数转换为
0
或1
:空值、假值、0
、0.0
、""
、[]
、空字节数组转换为0
,其余都转换为1
。
- to_bool(x)#
将参数转换为布尔值。以下转换为假值,其他所有值转换为真值:
null
false
0
,0.0
""
空字符串空字节数组
空 UUID (所有字节都为 0)
[]
空数组所有行为值为假的有效性
- to_uuid(x)#
将参数转换为 UUID。如果参数不是 UUID 或合法的 UUID 字符串表示,则报错。
- uuid_timestamp(x)#
从 UUID v1 中提取时间戳的浮点数,以秒为单位。如果 UUID 版本不是 1,则返回空值。若参数不是 UUID 则报错。
- is_null(x)#
测试参数是否为空值。
- is_int(x)#
测试参数是否为整数。
- is_float(x)#
测试参数是否为浮点数。
- is_finite(x)#
测试参数是否为有限的数字。
- is_infinite(x)#
测试参数是否为无穷的浮点数。
- is_nan(x)#
测试参数是否是特殊的浮点数
NAN
。
- is_num(x)#
测试参数是否为数字。
- is_bytes(x)#
测试参数是否为字节数组。
- is_list(x)#
测试参数是否为数组。
- is_string(x)#
测试参数是否为字符串。
- is_uuid(x)#
测试参数是否为 UUID。
随机函数#
- rand_float()#
返回在闭区间 [0, 1] 内均匀采样的浮点数。
- rand_bernoulli(p)#
返回随机的布尔值,以几率
p
返回真值。
- rand_int(lower, upper)#
返回所给闭区间内的随机整数,均匀采样。
- rand_choose(list)#
随机返回数组中的一个元素,随机采样。若数组为空则返回空值。
- rand_uuid_v1()#
生成一个随机的 UUID v1(包含当前时间戳)。在浏览器中的时间戳精度比原生程序的低很多。
- rand_uuid_v4()#
生成一个随机的 UUID v4。
正则表达式函数#
- regex_matches(x, reg)#
测试字符串能否被正则表达式匹配。
- regex_replace(x, reg, y)#
将字符串
x
中被正则表达式匹配上的第一处替换为y
。
- regex_replace_all(x, reg, y)#
将字符串
x
中被正则表达式匹配上的所有地方都替换为y
。
- regex_extract(x, reg)#
将字符串中所有被正则表达式匹配上的地方放在一个数组中返回。
- regex_extract_first(x, reg)#
返回字符串中被正则表达式匹配上的第一处。如果没有匹配则返回空值。
正则表达式语法#
单个字符:
. 除了换行之外的任何字符
\d 数字 (\p{Nd})
\D 非数字
\pN 单个字母表示的 Unicode 字符类
\p{Greek} Unicode 字符类
\PN 单个字母表示的 Unicode 字符类的补集
\P{Greek} Unicode 字符类的补集
字符集:
[xyz] 单个字符 x 或 y 或 z
[^xyz] 除了 x 、 y 、 z 以外的所有单个字符
[a-z] 在 a-z 范围内的单个字符
[[:alpha:]] ASCII 字符类([A-Za-z])
[[:^alpha:]] ASCII 字符类的补集([^A-Za-z])
[x[^xyz]] 包含潜逃的字符类
[a-y&&xyz] 交集(匹配 x 或 y)
[0-9&&[^4]] 使用交集与补集来做差异
[0-9--4] 差异(匹配 0-9,但是 4 除外)
[a-g~~b-h] 对称差异(仅匹配 a 与 h)
[\[\]] 字符集中的转义(匹配 [ 或 ])
组合:
xy 串联(x 后面紧接着 y)
x|y 交替(x 或者 y,都可以的时候优先 x)
重复:
x* 零或多个 x(贪婪匹配)
x+ 一或多个 x(贪婪匹配)
x? 零或一个 x(贪婪匹配)
x*? 零或多个 x(惰性匹配)
x+? 一或多个 x(惰性匹配)
x?? 零或一个 x(惰性匹配)
x{n,m} 至少 n 个,至多 m 个 x(贪婪匹配)
x{n,} 至少 n 个 x(贪婪匹配)
x{n} 正好 n 个 x(贪婪匹配)
x{n,m}? 至少 n 个,至多 m 个 x(惰性匹配)
x{n,}? 至少 n 个 x(惰性匹配)
x{n}? 正好 n 个 x(惰性匹配)
空匹配:
^ 文本起始处
$ 文本结束处
\A 仅文本起始处
\z 仅文本结束处
\b Unicode 词语边界(以 \w 开始,以 \W、\A 或 \z 结束)
\B 不是 Unicode 词语边界
时间戳函数#
- now()#
返回当前的 UNIX 时间戳(以秒计,浮点数)。浏览器中的精度比原生程序的低得多。
- format_timestamp(ts, tz?)#
将浮点数 UNIX 时间戳
ts
(以秒计)根据 RFC 3339 标准转换为字符串。若ts
为有效性,则使用其中以微秒计的整数时间戳。可选的第二个参数指定字符串显示的市区,格式为 UNIX 系统中的格式。
- parse_timestamp(str)#
根据 RFC 3339 标准将字符串转换为浮点数时间戳(以秒计)。