このブログは、旧・はてなダイアリー「檜山正幸のキマイラ飼育記 メモ編」(http://d.hatena.ne.jp/m-hiyama-memo/)のデータを移行・保存したものであり、今後(2019年1月以降)更新の予定はありません。

今後の更新は、新しいブログ http://m-hiyama-memo.hatenablog.com/ で行います。

JSON問い合わせ言語

説明文書としてはメチャクチャ出来が悪い。まーいいや。いつか書き直す。

[追記]あんまり意味がないところは取消線を付けた。[/追記]

●基本事項

関係から述語へ

JはJSONデータ全体の集合だとして、f:Jn→Boolean (Boolean = {true, false})を関係の特性関数と呼ぶ。以下、関係の特性関数を単に関係と呼ぶ。関係は部分関数でもよい。n = 0 のとき、つまり0項関係はブール定数なので相手にしない。n = 1 のときは述語、n = 2 なら二項関係、以下同様。

n項関係(ただし、n≧1)Fを、次の方法で、すべて二項関係fとみなす。

  1. F(x) に対して、f(x, 0) := F(x) とする。f:J×{0}→Boolean
  2. F(x, y)はそのまま。f(x, y) := F(x, y)
  3. F(x, y1, ..., yk) に対して、f(x, [y1, ..., yk]) := F(x, y1, ..., yk) とする。f:J×Array → Boolean

fは二項関係、aを定数として、φ(x) := f(x, a) の形で定義されるφをfの述語化と呼ぶ。φは1変数ブール値関数であると同時に、後で構文構成素としても使う。任意のn項関係Fから出発して、F→f、f→φ とすることにより、述語=一項関係が得られる。

φ をラムダ記法で書くと、φ = λx.f(x, a) となり、変数xは束縛され、自由変数(パラメータ)として残るのはaのみ、そこれで、φを @f a と書く。次が成立する。

  • φ(x) = (@f a)(x) = f(x, a)

パス修飾を持つ論理式

次が論理式の定義:

  1. 述語φは論理式である。
  2. Aが論理式のとき、¬A は論理式である。
  3. A, Bが論理式のとき、A∧B は論理式である。
  4. A, Bが論理式のとき、A∨B は論理式である。
  5. Aが論理式、pが単純JSONパスのとき、[p]A は論理式である。

[p]A 以外の論理式の解釈は通常通り。

Aが論理式のとき、JSONデータxに対して、A(x)が定義できる。not, and, or はブール演算だとする。x.p は、get(x, p) のようなパス式pによるアクセスの略記である。

  1. Aが述語φのとき、A(x) = φ(x)
  2. (¬A)(x) = not(A(x))
  3. (A∧B)(x) = and(A(x), B(x))
  4. (A∨B)(x) = or(A(x), B(x))
  5. ([p]A)(x) = A(x.p)

TはJの部分集合として、{x∈T | A(x)} を select from T where A とも書く。Tが集合でなく、リスト、バッグのときも同様の記法を使う。

●論理式のJSON表現

翻訳規則

  1. fが二項関係のとき、述語φ = λx.f(x, a) を @f a で示す。実際の構文では、関係名をすべて大文字にして先頭にアンダスコアを付ける。
  2. (¬A) の翻訳は、Aの翻訳にタグ @_NOT を付けたものである。
  3. (A∧B) の翻訳は、@_AND [Aの翻訳, Bの翻訳] である。
  4. (A∨B) の翻訳は、@_OR [Aの翻訳, Bの翻訳] である。

([p]A) の翻訳は、単純JSONパス式の構成に従って:

  1. pが名前αのとき、[α]A の翻訳は {α: Aの翻訳}
  2. pがインデックスiのとき、[i]A の翻訳は [..., Aの翻訳](i番目の項目)
  3. pがq.r の形のとき、[p]A の翻訳は、[q]X の翻訳に [r]A の翻訳を入れ子にする。

これは分かりにくいので、逆向きの翻訳と一緒に考えたほうがいい。

基本関係

基本関係を示す。

  • eq:J×J→Boolean は等号関係
  • like:String×String→Boolean はパターンマッチ(右がパターン)
  • tag:J×String→Boolean は、tag(x) == a のこと。
  • type:J×Strig→Boolean は、typeof(x) が a とマッチすること。typeofはタグを無視して型名を返す。typeofの値は、"null", "boolean", "number", "array", "object" のいずれか。ただし、typeには、"integer", "any" も渡せる。

●逆翻訳

aがJSONリテラルのとき、aを論理式に逆翻訳したものを【a】で示す。

スカラーリテラル

JSONスカラーcは、eq(x, c) を意味する。

  • 【c】 = λx.eq(x, c)

オブジェクトとプロパティ

α1などは、プロパティ名(文字列)、v1などはプロパティ値として:

  • 【{α1: v1, ..., αn : v1} 】 = λx.(【v1】(x[α1])∧...∧【vn】(x[αn])

プロパティ名 "*" は予約されていて、"*" : v は、明示されてないプロパティ名すべてに【v】を適用することを示す。

配列と項目

  • 【[v0, ..., vn] 】 = λx.(【v0】(x[0])∧...∧【vn】(x[n]))

ただし、最後の項目に特殊タグ @_REST が付いていたときは、次の解釈になる。

  • 【[v0, ..., @_REST vn] 】 = λx.(【v0】(x[0])∧...∧【vn-1】(x[n-1])∧【vn】(x[n])∧【vn】(x[n+1])∧...)

nより先のインデックスにはすべて【vn】が適用される。項目が1つしかないときは、@_REST の代わりに @_ALL が使える。

タグ

アンダスコアからはじまるタグは予約されていて、ユーザーレベルデータの中では使えないとする。αが通常のタグなら:

  • 【@α v】 = λx.[tag(x) = α ∧ 【v】(val(x))]

特殊タグ

述語に対応するタグは、プラグイン可能である(が、ユーザーにはたぶん解放しない)。次は予約された特殊タグになり、述語名には使えない。

  1. @_REST データ(配列の末尾のみ)
  2. @_ALL データ(配列の先頭のみ)
  3. @_NOT データ
  4. @_AND 配列
  5. @_OR 配列
  6. @_XOR 配列
  7. @_ANY 0
  8. @_ 0 (@_ANY 0 の短縮形)



[追記]ブツブツブツブツ:

@_TYPE "typename" はやめて、@_OBJECT, @_NUMBER などを使うほうがいい。

  • [@_INTEGER, @_INTEGER, @_REST @_STRING]

は、スキーマにすると:

  • array [integer, integer, string*]

だが、

  • [@_INTEGER, @_INTEGER]

は、tuple [integer, integer]を意味しない。array [integer, integer, any*] と同じ意味になる。

  • @_AND [@_LENGTH 2, [@_INTEGER, @_INTEGER]]

は酷すぎる。@_REST と対になる @_END(明示的に配列を終端する)を入れて

  • [@_INTEGER, @_INTEGER, @_END]

のほうがいいだろう。

キーボードを打った感触では、全部大文字はシフト押しっぱなしが嫌だな。

  • [@_Integer, @_Integer, @_End]

しかし、他のところで、$_CONTEXT とか使っているし。

  • [@_integer, @_integer, @_end]

これ書きやすい。が、視認性が悪い。

  • [@_REST @_GTEQ 0 ]

これは、合法だが気持ち悪い。

  • @_ALL @_GTEQ 0
  • [@_ALL @_GTEQ 0]
  • @_ALL [@_GTEQ 0]
  • @_EACH @_GTEQ 0
  • @_EACH [@_GTEQ 0]
  • @_LIST [@_GTEQ 0]

Catyスクリプトをしばらく使っていれば、@_EACH [@_GTEQ 0] が書きやすい気がする。

[/追記]