流沙河鎮

情報技術系のこと書きます。

q言語基礎_3_オペレータと予約語

# 以下は2020年頃に執筆した過去ブログのアーカイブです。現在メンテしておらず、一部の情報が古い可能性があります


へんてこデータベースもどき「kdb」と、知る人ぞ知るその実装言語「q」の基本を解説する本シリーズ。
本連載の目的はq言語の基本的な情報、実務で用いられる実践的なテクニックを日本語で分かりやすく提供することである。細かい情報や定義を知りたい時は適宜「q for mortals」及び「q Tips」を参照されたい

q for mortals
https://code.kx.com/q4m3/2_Basic_Data_Types_Atoms/

q Tips
https://www.amazon.com/Tips-Fast-Scalable-Maintainable-Kdb-ebook/dp/B00UZ8OMME

Operator

Operatorというのは”+”であるとか”-”といった、どの言語にもあるような記号のことだ。

q)1+2
3
q)2*2
4

しかし、qの世界において、Operatorは本質的に関数と同じものであり、プリミティブな処理系というわけではない。
qの世界における関数は、以下のように呼び出す。
f[x;y;z...]
従って、qの世界の+や-は以下のように使っても完全に正しい。

q)+[1;2]
3
q)*[2;2]
4

予約語

qにはbuilt in functionとして最初から予約語が用意されている関数が存在する。
これも、特別な宣言をしなくても使用可能であること以外は、通常の関数と性質は変わらない。
これまでに紹介したtypeは予約語の一種だ。

q)7 mod 2
1
q)
q)abs -42
42
評価における優先順位

qの世界において、式を評価する優先順位のルールは極めてシンプルである。
右から左へ評価する。
つまり、こういうことだ。

q)2*4-1
6

順序を制御したい場合は、以下のように括弧で括ってやればよい。
こうすることで、括弧の内側を先に評価させることが出来る。

q)(2*4)-1
7

何故右から左への評価という謎の仕様になっているのかについては4.1.2 Left-of-Right Evaluationこの辺りで熱弁されているが、我々qbie*1はあまり深く考えず、そういうものとして付き合っていけばよいと思われる。

関数への配列の活用

関数の引数には配列を渡すことも出来る。

q)+[1;1 2 3] /第二引数が配列
2 3 4
q)+[1 2 3;1] /第一引数が配列
2 3 4
q)+[1 2 3;1 2 3] /両方配列
2 4 6

色々なオペレータ、予約語

qコードを読書きする上で頻繁に使用するであろうオペレータを紹介する。

算術演算子

最も基本的な四則演算子は以下の通りで、特段難しいことはない。

q)1+2
3
q)5-1
4
q)2*3
6
q)10%5
2f
データが同じであるかを調べる

qの世界においてデータが同等であるかを調べる上では、Match~とEquality=の2つの概念がある。

Match~

Matchは2つのデータが型も含めて同等であるかを判定する。

q)50~50
1b
q)50~45+5
1b
q)50f~50i
0b /型が異なるので同じではない
q)50f~`50
0b /型が異なるので同じではない
q)(1 2;3 4)~(1;2 3 4)
0b /ネストしている配列の中身は同じではない
Equality=

Equalityは型を気にせず2つのデータが同じであるかを判定する。

q)50=50
1b
q)50f=50i
1b
q)`50=`50
1b
q)50=`50
'type
  [0]  50=`50
         ^        / symbolと他の型の比較はエラーになりできない

Not equal<>はEqualityの逆である。

q)50<>50
0b
q)50<>51
1b
反転させるnot

notは引数がtrueであればfalse、falseであればtrueを返す。
ただし、qの世界にはtrue/falseの予約語はなく、真偽はtrue=1b、false=0bのbooleanで示す。

q)true:1b
q)not true
0b
q)false:0b
q)not false
1b

booleanと他の数値型は透過的に扱えるので、以下のようになる。

q)true:1i
q)not true
0b
q)false:0i
q)not false
1b

実はqの世界では、0でない数値は全てtrueである。従って、0と1以外の数値データを渡した場合notは以下のような挙動を取る。

q)not 12i
0b
q)not -12
0b
q)not 0xff
0b
q)not "h"
0b
q)not "hoge"
0000b

charがnotで比較できるのは、それぞれの文字がASCII配列における数値として解されるためだ。

この特徴を活かしてif文が実装されることがよくあり、最初のうちは戸惑うかもしれない。
先取になるが、if節はif[条件式;処理n1;処理n2;処理n3...]という形で記述し、条件式がtrueである場合のみ以降の処理が実行される。

q)a:0
q)if[10;a:10] /10は0ではないのでtrue
q)a
10

q)a:0
q)if[0;a:10] /0なのでfalse
q)a
0
大小比較

大小比較の基本は何も難しいことはない。

q)10<20
1b
q)10>20
0b
q)10>=10
1b
q)10<=10
1b

文字(列)の比較はASCIIコードにおける数値の多寡で判定される。

q)"A"<"Z"
1b
q)"a"<"Z"
0b
q)"A"<"O"
1b
大きい方と小さい方 | , &

2つの引数に対して、|は"大きい"方の引数を返し、&は"小さい"方の引数を返す。
使いこなすと便利ではあるのだが、知らなければ見た目から挙動が連想しがたいため、初心者殺しのオペレータである。。。

q)1|2
2
q)1&2
1
q)1 2 3|4 5 6
4 5 6
q)1 2 3&4 5 6
1 2 3
q)1111111b|0101010b
1111111b
q)1111111b&1101010b
1101010b

その他にも様々なオペレータ、予約語があるが、頻繁に使用するのはこんなところだろう。
詳しくは、q for mortalsのoperators章を参照するといいだろう。
code.kx.com

*1:qの世界におけるnewbieの意で使われる