0. "Operators and Verbs Are Functions"

在q中,操作符(Operators)又称为动词(Verbs), 读表达式3+2按照从右到左的顺序:3 被加到 2,其中3是一个名词(主语),操作符+是一个动词,2是一个名词(宾语)。

1. 函数标识

下面介绍三种以后常见的函数分类:
monadic函数: f[x] 或者 f x
dyadic函数: g[x;y] 或者 x g y
atomic函数: 作用于数据结构的那个元素

例如+是一个dyadic函数,它有如下两种表达方法,都是等价的:

q) 2+3
q) +[2;3]

第二个式子很神奇,类似的表达方式还有:

q)=[2;3]
0b

更神奇的是,可以将二元运算符的前缀和中缀组合在一起:
q)(2+)[3]
5
q)(2+)3
5

2. atomic函数的拓展
用法见如下几个例子, 比较容易理解:

q)neg 1 2 3
-1 -2 -3
q)1 2 3+10 20 30
11 22 33
q)1 2 3+10 20 30 40
'length
q)100+1 2 3
101 102 103
q)1 2 3+100
101 102 103

1. 运算符优先级

没有运算符优先级!

1. Left-of-Right解读方法
由于q语言没有运算符优先级,但是有一个简单的法则来解读任何表达式:

Expressions are evaluated left-of-right
which equates to
Expressions are evaluated right-to-left

类似于解读复合函数f(g(x)), 可以被解读为f of g of x, 同样可以被解读为x to g to f

注意: 当表达式的结果是中缀运算符的左操作元时,必须对该表达式加括号,否则中缀运算符会作用在表达式最右边的一个元素上。如下例所示:

q)2*3+4
14
q)(2*3)+4
10
q)4+2*3
10

2. 没有运算符优先级的原因

  • 运算符优先级的开销较大,只有当解析完整个表达式后才能开始计算
  • 操作符的优先级往往会被括号所覆盖
  • 一些编程语言允许用户自定义dyadic运算符,这就需要拓展运算符的优先级别来cover用户定义的运算符,这就导致了复杂性。

2. Match

作用于任意两个q元素,当两个元素相同(identical)时返回1b, 不同时返回0b。对于相互match的两个元素,它们需要同样的类型,同样的大小,同样的值, 但也可能占据不同的储存空间,这也意味着,拷贝项在q中被认为是相同的。

q)42~40+2
1b
q)42~42h
0b
q)42f~42.0
1b
q)42~`42
0b
q)`42~"42"
0b
q)4 2~2 4
0b
q)42~(4 2;(1 0))
0b
q)(4 2)~(4;2*1)
1b
q)(())~enlist ()
0b
q)(1; 2 3 4)~(1; (2; 3; 4))
1b
q)(1 2;3 4)~(1;2 3 4)
0b

3. 相等和关系运算符

1. 相等=和不等<>
相等运算符=和Match运算符~不同之处在于,相等运算符=atom-wise的,即atomic函数。

相等运算符校验的是两个元素是否是值相等的,并不管元素的类型:

q)42=42i
1b
q)42=42.0
1b
q)42=0x42
0b
q)42="*"
1b

最后一项说明了,char "*"的underlying值和42的underlying值是一样的。

但对于日期类型,比较的是时间上的先后关系,而不是其underlying值

q)2000.01.01=2000.01.01D00:00:00.000000000
1b
q)2015.01.01<2015.02m
1b
q)12:00:00=12:00:00.000
1b

对于float元素的对比,q语言的容限是10^-14

2. 非零 not
如果对应元素的underlying值是0,则返回1b;否则返回0b。

对于char类型,"\000"为0;对于时间类型,千禧年0时刻的值为0。

3. 大小关系符 >, <=, >, >=
对于char类型和numeric类型的比较,比较的是其underlying的数值。

symbol的比较按照字典序:

q)`a<`b
1b
q)`abc<`aba
0b

4.基础数学运算符 +, -, *, %

与其它编程语言不同的是,在q语言中使用%而不是/代表除法,因为/被用来作为注释的分隔符,而且q god认为%更接近与除号÷。 :)

除号返回的结果总是float类型。

5. 最大| 和最小&

|返回左右运算元的最大元素,对于二元数据来说,可以简化为逻辑运算符or&返回左右运算元的最小元素,对于二元数据,简化为and

q)42|43
43
q)0b|1b
1b
q)1b&0b
0b
q)42|0x2b
43
q)"a"|"z"
"z"
q)`a|`z / error
'type

|&操作同样是item-wise的,如下例:

q)2|0 1 2 3 4
2 2 2 3 4
q)11010101b&01100101b
01000101b
q)"zaphod"|"arthur"
"zrthur"

对于二元数据的可读性,|可以被写为or&可以被写为and

q)42 or 43
43

6. 修订符(Amend) :

一个对:的重载是inplace 赋值

q)a:42

类似与C语言中的+=,-=等,在q语言中,同样有+:, -:, &=,均表示inplace赋值

即使变量尚未被创建,也可以使用amend形式:

q)x
'x
q)x+:42
q)x
42

一个非常有用的形式是,:,对list进行inplace的append操作:

q)L:1 2 3
q)L,:4
q)L
1 2 3 4

Amend会自动做类型提升,除了,:

q)L:1.1 2 2 3.3
q)L[1]+:100
q)L,:100
'type

7. 指数基元: sqrt, exp, log, xexp, xlog

sqrtexp与传统编程语言相同,log则是以自然对数e为底的。

xexp代表乘方, xlog代表以左运算元为底的对数

q)2 xexp 5
32f
q)-2 xexp .5
0n
q)2 xlog 32
5f
q)2 xlog -1
0n

8. 更多的数学运算基元

1. 商div 和 余数mod
div的结果是向下取整, mod的计算公式是dividend – (dividend div divisor)

q)7 div 2
3
q)7 div 2.5
2
q)-7 div 2
-4

q)7 mod 2.5
2
q)-7 mod 2
1
q)7 mod 2 3 4
1 1 3

2. 取符号signum
其结果返回1i代表正,-1i代表负,0i代表0.

3. 倒数 reciprocal

q)reciprocal 0.02380952
42.00001
q)reciprocal 0.0
0w
q)reciprocal -0.0
-0w

4. floorceiling
floor向下取整, ceiling向上取整, 用floor可以规整浮点数类型的位数

q)x:4.242
q)0.01floor 100x
4.24
For reasons known only to the q gods, floor and ceiling do not apply to short types.
q)floor 4h
'type 

9. 时间类型的操作符

对同种时间类型的数据比较是针对其underlying的数值进行的;对于不同时间类型的数据,q会先将他们转换到同种类型再对其underlying值作比较。

一些常见的操作:

q)2015.01.01+12:00:00.000000000
2015.01.01D12:00:00.000000000

q)2015.01.01D00:00:00.000000000-2014.01.01D00:00:00.000000000
365D00:00:00.000000000
q)12:00:00-11:00:00
1:00:00
q)12:00-11:00
1:00

10. 对infnull的操作

float和int的inf对应的二进制表示如下:

Value        Bit Representation
 0Wh          0111111111111111b
-0Wh          1000000000000001b
 0Wi    01111111111111111111111111111111b
-0Wi    10000000000000000000000000000001b
 0W    0111111111111111111111111111111111111111111111111111111111111111b
-0W    1000000000000000000000000000000000000000000000000000000000000001b

所有的null值都相等(=),因为它们都代表缺失值,但并不match(~),因为类型不同。

NaN值都相等,并且not对所有的null值和inf值都返回0b,因为它们都不等于0.

q)not 0W
0b
q)not -0w
0b
q)not 0N
0b

对于任何数值类型:null < negtative infinity < normal values < positive infinity

对于inf值的大小,取决于他们类型的宽度,对于正无穷: short < int < long < real < float, 对于负无穷:-float < -real < -long < -int < -short

q)0W<0w
1b
q)-0w<0W
1b
q)-10000000<0N
0b
q)0N<42i
1b
q)0n<-0w
1b

11. 别名(Alias) ::

一个alias是一个表达式——它并不是表达式的结果,而是表达式本身。
1. 创建别名::
如下ba别名,当a改变时,b的值也跟着改变,但c不会改变。

q)a:42
q)b::a
q)c:a
q)a:43
q)b
43
q)c
42

下面是一个更有趣的例子:

q)w::(x*x)+y*y
q)x:3
q)y:4
q)w
25
q)y:5
q)w
34

注意:只有当alais所依赖的变量发生变化时,才会被重新计算(re-evaluated)。

2. 别名 vs. 函数
我们可以定义函数如下

q)fu:{(x*x)+y*y}
q)fu[3;4]
25

别名和函数的区别在于:

  1. 函数需要提供明确的参数;而对别名,你可以在程序的任意地方对变量赋值,而且当且仅当别名被引用时,表达式才会被计算。
  2. 函数并不保存计算结果,而别名保存计算结果。

3. 依赖关系
别名依赖其表达式中的变量。其依赖关系储存在系统字典中,可以通过命令.z.b或者命令\b来获取。

q)w::(x*x)+y*y
q).z.b
x| w
y| w

4. 视图 view
别名常被用来创建一个数据库的视图:

q)t:([]c1:`a`b`c`a;c2:20 15 10 20;c3:99.5 99.45 99.42 99.4)
q)v::select sym:c1,px:c3 from t where c1=`a
q)v
sym px
--------
a 99.5
a 99.4
q)update c3:42.0 from `t where c1=`a
`t
q)v
sym px
------
a   42
a   42

表的依赖项可以通过.z.b查看:

q).z.b
t| v

End.


Sergeant
1 声望0 粉丝