2020年3月31日火曜日

Kaleidox: モデル駆動開発

Kaleidoxはモデル駆動開発のアクション言語を指向しています。実用言語の観点から、データ操作の枠組みとしてRecordとTableを中心とした機能群を用意しています。

一方、モデル駆動開発に適用するためにはモデル側との連携も必要になります。

今回はモデル駆動開発のためのモデル定義とアクション言語の連携について、現時点で実装している簡単な機能を例に探っていきます。

初期設定

以下のinit.kldを用意します。

* env

db.default.driver="org.h2.Driver"
db.default.url="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"

* voucher

** City

#+caption: 特性一覧
| 特性 | 名前                | 型     | 多重度 | ラベル       |
|------+---------------------+--------+--------+--------------|
| 属性 | name                | int    |      1 | 都市 |
| 属性 | latitude            | string |      1 | 緯度         |
| 属性 | longitude           | int    |      1 | 経度         |
| 属性 | average_temperature | int    |      1 | 平均気温     |
| 属性 | precipitation       | int    |      1 | 降水量       |

* prologue

store-create 'City 'city

この初期設定により以下の設定が行われます。

  • メモリDBの初期化
  • モデルの定義
  • モデルに従ったデータベースのテーブルの作成
メモリDBの初期化

envセクションで組み込みRDBのH2をメモリモードで起動するように記述しています。

モデルの定義

voucherセクションでモデルの定義を行っています。

モデルに従ったデータベースのテーブルの作成

prologueセクションでテーブルを作成する記述を行っています。

モデル

voucherセクションで以下のモデルを記述しています。

ボクは2008年ごろから帳票指向アーキテクチャをターゲットにしたモデリングの手法SimpleModelingを整備しています。

SimpleModelingではSimpleModelerというモデルコンパイラでプログラムの自動生成を行うことが可能です。

voucherはSimpleModelingのアーキタイプで「伝票」を記述するためのモデルです。一般のOOADではValue ObjectやDTO(Data Transfer Object)という方向性のモデルです。

SimpleModelingでは、voucher以外にも多数の種類のモデルを定義していますが、現時点ではKaleidoxではvoucherのみサポートしています。

現在SimpleModelerの新版を開発中で、これをKaleidoxに組み込めば各種モデルの操作をKaleidoxで行うことができるようになる予定ですが、現在は暫定的にvoucherのみ扱い可能にしています。

voucherセクションで定義しているvoucherは都市の緯度・経度、平均気温、降水量を定義した以下のものです。

* voucher

** City

#+caption: 特性一覧
| 特性 | 名前                | 型     | 多重度 | ラベル       |
|------+---------------------+--------+--------+--------------|
| 属性 | name                | int    |      1 | 都市 |
| 属性 | latitude            | string |      1 | 緯度         |
| 属性 | longitude           | int    |      1 | 経度         |
| 属性 | average_temperature | int    |      1 | 平均気温     |
| 属性 | precipitation       | int    |      1 | 降水量       |

この表の定義によってvoucher Cityが定義されます。

テーブルの作成

前述のinit.kldのprologueセクションは以下になっています。

* prologue

store-create 'City

store-create関数はテーブルの作成を行います。第1引数にモデル名Cityを指定しています。

このためKaleidox起動時にprologueセクションでこのstore-create関数が実行され、バウチャーCityのモデル定義に従ったテーブルCityがメモリDB内に作成されます。

今回はテスト目的でメモリDBを使用していますが、MySQLなどのRDBを使う場合にすでにテーブルが作成されている場合はこの処理は不要です。

データ格納

init.kldの設定によりKaleidox起動後はテーブルcityが作成されています。このテーブルにデータの格納を行ってみます。

都市,緯度,経度,平均気温,降水量
札幌,43.055248,141.345505,8.0,1158
仙台,38.254162,140.891403,11.9,1219
東京,35.680909,139.767372,15.3,1460
名古屋,35.154919,136.920593,14.9,1575
大阪,34.702509,135.496505,16.2,1400
広島,34.377560,132.444794,15.0,1603
福岡,33.579788,130.402405,16.0,1690
那覇,26.204830,127.692398,22.4,2128

「file:city.csv」によりcity.csvを読み込みます。 city.csvはTableオブジェクトとして読み込まれます。

kaleidox> file:city.csv
Table[5x8]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━┓
┃都市  │緯度     │経度      │平均気温│降水量┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━┿━━━━━━┫
┃札幌  │43.055248│141.345505│8.0     │1158  ┃
┃仙台  │38.254162│140.891403│11.9    │1219  ┃
┃東京  │35.680909│139.767372│15.3    │1460  ┃
┃名古屋│35.154919│136.920593│14.9    │1575  ┃
┃大阪  │34.702509│135.496505│16.2    │1400  ┃
┃広島  │34.377560│132.444794│15.0    │1603  ┃
┃福岡  │33.579788│130.402405│16.0    │1690  ┃
┃那覇  │26.204830│127.692398│22.4    │2128  ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━┛

読み込んだTableオブジェクトをテーブルCityに書き込みます。

Tableのヘッダにあるカラム名をキーにしてテーブルに書き込みます。このカラム名はVoucherモデルの名前だけでなくラベルとも照合されます。

たとえばVoucherモデルの定義ではCityオブジェクトの都市名を格納する属性はnameですが、ラベルが「都市」になっています。このためTableオブジェクトのカラム名nameだけでなくカラム名「都市」も格納対象となります。他のカラムも同様に、Cityオブジェクトの各属性とも対応付けられます。そして、Cityオブジェクトを格納するCityテーブルの該当するカラムとの対応付けも行われます。

テーブルへの追加格納はstore-insert関数で行います。

第1引数にテーブル名、第2引数にTableオブジェクトを指定します。ここではTableオブジェクトの読み込み直後で、Tableオブジェクトがスタックの先頭に積まれているので第2引数を省略してスタック上のTableオブジェクトを指定しています。

kaleidox> store-insert 'City
(0 0 0 0 0 0 0 0)

store-insert関数の返却値は新規作成したレコードのIDのリストです。CityテーブルはIDを持たないテーブルのためレコード数分の0を要素として持つリストが返されています。

データの読み込み

store-select関数でテーブルに格納したデータを読み込みます。

kaleidox> store-select 'City
Table[5x10]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━┓
┃name  │latitude │longitude │average_temperature│precipitation┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━┫
┃札幌  │43.055248│141.345505│8.0                │1158.0       ┃
┃仙台  │38.254162│140.891403│11.9               │1219.0       ┃
┃東京  │35.680909│139.767372│15.3               │1460.0       ┃
┃名古屋│35.154919│136.920593│14.9               │1575.0       ┃
┃大阪  │34.702509│135.496505│16.2               │1400.0       ┃
┃広島  │34.37756 │132.444794│15.0               │1603.0       ┃
┃福岡  │33.579788│130.402405│16.0               │1690.0       ┃
┃那覇  │26.20483 │127.692398│22.4               │2128.0       ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━┛

store-select関数のデフォルト動作ではモデルの属性名が使用されます。このため、都市はname、緯度はlatitudeといったヘッダ名を使用したTableオブジェクトとなっています。

プログラム的にデータを処理する場合はこの方が都合がよいですが、外部出力を行う場合はモデル側のラベル名がTableオブジェクトのヘッダ名になっている方が便利です。

このための指定を行うオプションとしてstore-select関数ではtable-headerスイッチを用意しています。

以下では(Lispの)キーワード指定によってtable-headerスイッチにlabelを指定しています。このためstore-select関数では、データを読み込むTableオブジェクトのカラム名をモデルのラベル名にしています。

kaleidox> store-select :table-header 'label 'City
Table[5x10]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━┓
┃都市  │緯度     │経度      │平均気温│降水量┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━┿━━━━━━┫
┃札幌  │43.055248│141.345505│8.0     │1158.0┃
┃仙台  │38.254162│140.891403│11.9    │1219.0┃
┃東京  │35.680909│139.767372│15.3    │1460.0┃
┃名古屋│35.154919│136.920593│14.9    │1575.0┃
┃大阪  │34.702509│135.496505│16.2    │1400.0┃
┃広島  │34.37756 │132.444794│15.0    │1603.0┃
┃福岡  │33.579788│130.402405│16.0    │1690.0┃
┃那覇  │26.20483 │127.692398│22.4    │2128.0┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━┛

チャート表示

最後に、テーブルから読み込んでみたデータをチャートに表示しましょう。ここからは前回「Kaleidox/単回帰分析」と同じ処理です。詳細はそちらを参照してください。

まずTableオブジェクトからチャートに表示するデータを抽出します。

kaleidox> table-select 0,1,3 x
Table[3x8]
kaleidox> :show:print
Table[3x8]
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━┓
┃都市  │緯度     │平均気温┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━┫
┃札幌  │43.055248│8.0     ┃
┃仙台  │38.254162│11.9    ┃
┃東京  │35.680909│15.3    ┃
┃名古屋│35.154919│14.9    ┃
┃大阪  │34.702509│16.2    ┃
┃広島  │34.377560│15.0    ┃
┃福岡  │33.579788│16.0    ┃
┃那覇  │26.204830│22.4    ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━┛

このTableオブジェクトをtable-chart関数でチャートに表示します。

まず、抽出後のTableオブジェクトを変数xに束縛します。Tableオブジェクトは抽出直後なのでスタックの先頭に積まれています。setq関数の第2引数を省略することでスタック上のTableオブジェクトが束縛対象となります。

kaleidox> setq x
kaleidox> table-chart x

以下のようなチャートが表示されます。


また単回帰分析を行う場合はanalyzeスイッチにsimple-regressionを指定します。

kaleidox> table-chart :analyze 'simple-regression x

以下のようなチャートが表示されます。


まとめ

頭出しレベルですが、モデル駆動開発のイメージを確認するために簡単な連携例を説明しました。

基本的な方向性としては、モデル定義を行った後は簡単なアクション言語による記述のみでアプリケーションを記述したいということです。

モデル定義がのままプログラミングにつながることで、モデルをプログラムに翻訳することによって起きているプログラミングの工数を大幅に低減することできます。また、これと同じぐらい重要なのはモデルとプログラムのインピーダンスミスマッチをなくすることができることです。モデルとプログラミングが一体となることで、よりモデリングに集中することができます。

SimpleModelerの改版版は現在開発中ですが、これをKaleidoxに組み込むことでより広範囲のモデルをモデル駆動の対象としてアプリケーション開発に活用できることができるようになります。

諸元

  • Kaleidox : 0.1.10
気象データ

以下のページ「5.おもな都市の月平均気温・月降水量」のデータを使用しました。

http://www.biodic.go.jp/reports/2-2/hyo/aa126_001.html

2020年2月29日土曜日

Kaleidox: 単回帰分析

KaleidoxプログラムではTableオブジェクトとRecordオブジェクトを中心に演算を行っていきます。

このためTableオブジェクトとRecordオブジェクトを操作するための機能を多数サポートする予定にしています。

今回はそういった便利な機能の中で、Tableオブジェクトのチャート表示と単回帰分析機能について説明します。

データ

単回帰分析を行う対象のデータをCSVファイルcity.csvとして用意しました。このデータでは日本の都市の緯度経度と平均気温、降水量を記述しています。

都市,緯度,経度,平均気温,降水量
札幌,43.055248,141.345505,8.0,1158
仙台,38.254162,140.891403,11.9,1219
東京,35.680909,139.767372,15.3,1460
名古屋,35.154919,136.920593,14.9,1575
大阪,34.702509,135.496505,16.2,1400
広島,34.377560,132.444794,15.0,1603
福岡,33.579788,130.402405,16.0,1690
那覇,26.204830,127.692398,22.4,2128

データの読み込み

KaleidoxのREPLからURIリテラルで上記CSVファイル名を投入すると、データを読み込んだTableオブジェクトが生成されます。

kaleidox> file:city.csv
Table[5x8]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━┓
┃都市  │緯度     │経度      │平均気温│降水量┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━┿━━━━━━┫
┃札幌  │43.055248│141.345505│8.0     │1158  ┃
┃仙台  │38.254162│140.891403│11.9    │1219  ┃
┃東京  │35.680909│139.767372│15.3    │1460  ┃
┃名古屋│35.154919│136.920593│14.9    │1575  ┃
┃大阪  │34.702509│135.496505│16.2    │1400  ┃
┃広島  │34.377560│132.444794│15.0    │1603  ┃
┃福岡  │33.579788│130.402405│16.0    │1690  ┃
┃那覇  │26.204830│127.692398│22.4    │2128  ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━┛

table-chart関数

データを読み込んだ直後にtable-chart関数を投入すると、以下に示すようにTableオブジェクトから必要な情報を取得して散布図を表示します。

kaleidox> table-chart

デフォルトでは表の第1列を項目名、第2列をX軸、第3列をY軸と解釈して自動でデータを読み込みます。

Kaleidoxは関数の投入結果をスタックとヒストリに保存しています。table-chart関数を引数なしで起動するとスタックの先頭にあるオブジェクトを引数として使用するのでこのようなことが可能になっています。

historyコマンドで確認するとCSVファイルをローディングした結果のTableオブジェクトは6番目に格納されていました。今後はヒストリの6番目のTableオブジェクトを使用します。

kaleidox> :history
 1: nil
 2: Table[3x10]
 3: Matrix[1x10]
 4: Matrix[2x10]
 5: Matrix[1x2]
 6: Table[5x8]
 7: Window

行列

回帰分析のような数値演算を行う場合、通常はTableオブジェクトを行列に変換してから行列に対して線形代数の演算を行っていきます。

Kaleidoxの場合はtable-matrix関数でTableオブジェクトから行列を抽出することができます。

kaleidox> table-matrix #6
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌                                ┐
│43.055248 141.345505 8.0  1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756  132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483  127.692398 22.4 2128.0│
└                                ┘

この例から分かるように、Tableオブジェクトの持つ表データのヘッダ行と数値以外の情報が入っている列を取り除いた情報を行列に再構築してくれます。

ただし今回は行列は使用しません。

table-select関数

回帰分析のような数値演算を行う場合、通常はMatrixオブジェクトを使用しますが、単回帰分析のような定番の分析手法は表に対して直接使用できるようになっています。

この記事の先頭でtable-chart関数によってTableオブジェクトの内容から自動抽出した情報を散布図として表示する操作を行いました。

この散布図に回帰分析の結果を重ねて表示してみることにします。

file.csvのデータをそのまま使ってもよいのですが、都市の緯度と経度に対して単回帰分析を行っても面白くないので、都市の緯度と平均気温に対して単回帰分析を行ってみます。

まずTableデータの第1列に都市名、第2列に緯度、第3列に平均気温を取るTableオブジェクトを生成します。これはtable-chart関数が散布図を描く時に、デフォルトでは第1列に項目名、第2列にX軸の値、第3列にY軸の値を想定しているためです。

この変換はtable-select関数で行うことができます。以下の例ではtable-select関数の引数に範囲オブジェクト「0,1,3」を指定しています。この結果オリジナルの表の第1列、第2列、第4列の内容をこの順番で並べたTableオブジェクトが生成されます。なお範囲オブジェクトの添字は0ベース、表の表現では添字は1ベースで表現しています。

kaleidox> table-select 0,1,3 #6
Table[3x8]
kaleidox> :show:print
Table[3x8]
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━┓
┃都市  │緯度     │平均気温┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━┫
┃札幌  │43.055248│8.0     ┃
┃仙台  │38.254162│11.9    ┃
┃東京  │35.680909│15.3    ┃
┃名古屋│35.154919│14.9    ┃
┃大阪  │34.702509│16.2    ┃
┃広島  │34.377560│15.0    ┃
┃福岡  │33.579788│16.0    ┃
┃那覇  │26.204830│22.4    ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━┛

このTableオブジェクトに対してtable-chart関数を適用すると以下の散布図が表示されました。

kaleidox> table-chart

単回帰分析

単回帰分析を行った結果をチャート上に表示する場合はanalyzeオプションにsimple-regressionを指定します。

先程作成したTableオブジェクトのヒストリを確認します。

:history
 1: nil
 2: Table[3x10]
 3: Matrix[1x10]
 4: Matrix[2x10]
 5: Matrix[1x2]
 6: Table[5x8]
 7: Window
 8: Table[3x8]

8番目にあることが分かったので「#8」でアクセスすることができます。

単回帰分析の結果を散布図上に表示するためにはanalyzeオプションにsimple-regressionを指定します。

kaleidox> table-chart :analyze 'simple-regression #8

上記のtable-chart関数の結果、以下の単回帰分析付きの散布図が表示されました。


まとめ

CSVファイルから読み込んだTableオブジェクトに対して、table-selection関数による簡単な加工のみで散布図の表示、単回帰分析の結果表示を行うことができました。

通常のプログラミング言語でこの処理を行うとCSVファイルの読み込み、チャート機能の利用、数値演算処理による単回帰分析など案外大変なコーディングが必要になりますが、Kaleidoxではあっさりと実現できました。

このようなことが可能になるのは、Kaleidoxで汎用データ構造であるTableオブジェクトを言語の中軸機能と位置付け、Tableオブジェクトを対象にさまざまな関数を用意しているからです。

Kaleidoxはアクション言語として設計していますが、PIM(Platform Independent Model)的な抽象処理のみが記述できるだけだと実用性に乏しくなります。そういった抽象的な機能と同時に今回のTableデータ処理のような地味な実用機能もサポートし、シームレスに連携できることが必要だと考えています。

諸元

  • Kaleidox : 0.1.10
気象データ

以下のページ「5.おもな都市の月平均気温・月降水量」のデータを使用しました。

http://www.biodic.go.jp/reports/2-2/hyo/aa126_001.html

2020年1月31日金曜日

Kaleidox: Matrix

BigDataやAIなどがアプリケーションを構成する重要部品となってきています。このBigDataやAIをアプリケーションで扱う上で重要な技術要素として行列(matrix)があります。

Kaleidoxでは行列をMatrixオブジェクトとして記述して各種行列演算をすることができます。

入力

Matrixオブジェクトの入力方法として以下の方法について見ていきます。

  • Matrixリテラル
  • matrix-load関数
Matrixリテラル

Matrixオブジェクトのリテラルは以下のように二重のカギ括弧で囲まれたエリアに改行と空白を区切り記号として記述したものです。

[[
43.055248 141.345505 8.0 1158
38.254162 140.891403 11.9 1219
35.680909 139.767372 15.3 1460
35.154919 136.920593 14.9 1575
34.702509 135.496505 16.2 1400
34.377560 132.444794 15.0 1603
33.579788 130.402405 16.0 1690
26.204830 127.692398 22.4 2128
]]

REPLから入力すると以下のようになります。

kaleidox> [[
43.055248 141.345505 8.0 1158
38.254162 140.891403 11.9 1219
35.680909 139.767372 15.3 1460
35.154919 136.920593 14.9 1575
34.702509 135.496505 16.2 1400
34.377560 132.444794 15.0 1603
33.579788 130.402405 16.0 1690
26.204830 127.692398 22.4 2128
]]
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌                                ┐
│43.055248 141.345505 8.0  1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756  132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483  127.692398 22.4 2128.0│
└                                ┘
matrix-load関数

matrix-load関数でCSVファイルの内容からMatrixオブジェクトを生成します。matrix-load関数では内容の中から自動的に行列化可能な数値部分を取り出してMatrixオブジェクトにします。

日本の都市について緯度経度と平均気温、降水量を記述したCSVファイル city.csv を用意します。

都市,緯度,経度,平均気温,降水量
札幌,43.055248,141.345505,8.0,1158
仙台,38.254162,140.891403,11.9,1219
東京,35.680909,139.767372,15.3,1460
名古屋,35.154919,136.920593,14.9,1575
大阪,34.702509,135.496505,16.2,1400
広島,34.377560,132.444794,15.0,1603
福岡,33.579788,130.402405,16.0,1690
那覇,26.204830,127.692398,22.4,2128

matrix-load関数を使うと以下のようにMatrixオブジェクトを取得することができます。

kaleidox> matrix-load file:city.csv
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌                                ┐
│43.055248 141.345505 8.0  1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756  132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483  127.692398 22.4 2128.0│
└                                ┘
Tableオブジェクト

TableオブジェクトからMatrixオブジェクトを取得することができます。

引き続きCSVファイル city.csv を使用します。

都市,緯度,経度,平均気温,降水量
札幌,43.055248,141.345505,8.0,1158
仙台,38.254162,140.891403,11.9,1219
東京,35.680909,139.767372,15.3,1460
名古屋,35.154919,136.920593,14.9,1575
大阪,34.702509,135.496505,16.2,1400
広島,34.377560,132.444794,15.0,1603
福岡,33.579788,130.402405,16.0,1690
那覇,26.204830,127.692398,22.4,2128

このCSVファイルをtable-load関数を使ってTableオブジェクトとして読み込みます。

kaleidox> table-load file:city.csv
Table[5x8]
kaleidox> :show:print
┏━━━━━━┯━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━┓
┃都市  │緯度     │経度      │平均気温│降水量┃
┣━━━━━━┿━━━━━━━━━┿━━━━━━━━━━┿━━━━━━━━┿━━━━━━┫
┃札幌  │43.055248│141.345505│8.0     │1158  ┃
┃仙台  │38.254162│140.891403│11.9    │1219  ┃
┃東京  │35.680909│139.767372│15.3    │1460  ┃
┃名古屋│35.154919│136.920593│14.9    │1575  ┃
┃大阪  │34.702509│135.496505│16.2    │1400  ┃
┃広島  │34.377560│132.444794│15.0    │1603  ┃
┃福岡  │33.579788│130.402405│16.0    │1690  ┃
┃那覇  │26.204830│127.692398│22.4    │2128  ┃
┗━━━━━━┷━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━┛

Tableオブジェクトを起点にさまざまな操作を行うことができますが、ここではmatrixメソッドを使用してMatrixオブジェクトに変換しています。matrix-load関数と同様に行列化可能なデータを抽出してMatrixオブジェクト化しています。

kaleidox> .matrix
Matrix[0x8]
kaleidox> :show
Matrix[4x8]
┌                                ┐
│43.055248 141.345505 8.0  1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756  132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483  127.692398 22.4 2128.0│
└                                ┘

参照

Matrixオブジェクトを参照して各種データを取得することができます。

準備としてcity.csvに入っているデータをMatrix化したものを変数xに束縛します。

kaleidox> setq x (matrix-load file:city.csv)
Matrix[4x8]
kaleidox> x
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌                                ┐
│43.055248 141.345505 8.0  1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756  132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483  127.692398 22.4 2128.0│
└                                ┘
行の参照

Matrixオブジェクトの行はrowメソッドで取得することができます。引数に行番号を指定します。行番号は0始まりです。

kaleidox> x.row(0)
[43.055248 141.345505 8.0 1158.0]
列の参照

Matrixオブジェクトの列はcolumnメソッドで取得することができます。引数に列番号を指定します。列番号は0始まりです。

kaleidox> x.column(3)
[1158.0 1219.0 1460.0 1575.0 1400.0 1603.0 1690.0 2128.0]
データの参照

Matrixオブジェクトのデータはatメソッドで取得することができます。引数に列番号、行番号を指定します。

kaleidox> x.at(2,3)
14.9

演算

準備として2✕2の正方行列を変数xに束縛します。

kaleidox> setq x [[
1 2
3 4
]]
Matrix[2x2]
kaleidox> :show
Matrix[2x2]
┌       ┐
│1.0 2.0│
│3.0 4.0│
└       ┘
加算

加算は+メソッドです。

kaleidox>+ x x
Matrix[2x2]
kaleidox> :show
Matrix[2x2]
┌       ┐
│2.0 4.0│
│6.0 8.0│
└       ┘
積算

積算は*メソッドです。

kaleidox> * x x
Matrix[2x2]
kaleidox> :show
Matrix[2x2]
┌         ┐
│7.0  10.0│
│15.0 22.0│
└         ┘
逆行列

逆行列はinvメソッドで行います。

kaleidox> x.inv
Matrix[2x2]
kaleidox> :show
Matrix[2x2]
┌                                       ┐
│-1.9999999999999996 0.9999999999999998 │
│1.4999999999999998  -0.4999999999999999│
└                                       ┘
ランク

行列のランクはrankメソッドで取得します。

kaleidox> x.rank
2

出力

Matrixオブジェクトの出力方法として以下の方法について見ていきます。

  • matrix-save関数
  • Table

準備としてcity.csvに入っているデータをMatrix化したものを変数xに束縛します。

kaleidox> setq x (matrix-load file:city.csv)
Matrix[4x8]
kaleidox> x
Matrix[4x8]
kaleidox> :show
Matrix[4x8]
┌                                ┐
│43.055248 141.345505 8.0  1158.0│
│38.254162 140.891403 11.9 1219.0│
│35.680909 139.767372 15.3 1460.0│
│35.154919 136.920593 14.9 1575.0│
│34.702509 135.496505 16.2 1400.0│
│34.37756  132.444794 15.0 1603.0│
│33.579788 130.402405 16.0 1690.0│
│26.20483  127.692398 22.4 2128.0│
└                                ┘
matrix-save関数

Matrixオブジェクトはmatrix-save関数を使ってCSV形式でファイルに保存することができます。

第1引数に保存するファイル名、第2引数にMatrixオブジェクトを指定します。

kaleidox> matrix-save file:output.csv x
t

matrix-save関数で保存したCSVファイルoutput.csvには以下のCSVが格納されます。

"43.055248","141.345505","8.0","1158.0"
"38.254162","140.891403","11.9","1219.0"
"35.680909","139.767372","15.3","1460.0"
"35.154919","136.920593","14.9","1575.0"
"34.702509","135.496505","16.2","1400.0"
"34.37756","132.444794","15.0","1603.0"
"33.579788","130.402405","16.0","1690.0"
"26.20483","127.692398","22.4","2128.0"
Table

Matrixオブジェクトのtableメソッドで行列データをTableオブジェクトに変換することできます。表のカラム名は1からの連番となります。

kaleidox> x.table
Table[4x8]
kaleidox> :show:print
┏━━━━━━━━━┯━━━━━━━━━━┯━━━━┯━━━━━━┓
┃1        │2         │3   │4     ┃
┣━━━━━━━━━┿━━━━━━━━━━┿━━━━┿━━━━━━┫
┃43.055248│141.345505│8.0 │1158.0┃
┃38.254162│140.891403│11.9│1219.0┃
┃35.680909│139.767372│15.3│1460.0┃
┃35.154919│136.920593│14.9│1575.0┃
┃34.702509│135.496505│16.2│1400.0┃
┃34.37756 │132.444794│15.0│1603.0┃
┃33.579788│130.402405│16.0│1690.0┃
┃26.20483 │127.692398│22.4│2128.0┃
┗━━━━━━━━━┷━━━━━━━━━━┷━━━━┷━━━━━━┛

Tableオブジェクトを起点にMatrixオブジェクトによる行列演算の結果を各種応用に利用していくことができます。

まとめ

今回はKaleidoxで行列を扱うMatrixオブジェクトについて説明しました。

Matrixの演算に加えて、CSVによる外部入出力、Tableオブジェクトとの連携を容易に行うことができます。モデル駆動開発の場合でも、BigDataやAIの応用を考えた場合、アクション言語ではドメインモデルと行列を併用してシームレスに連携できる必要があるはずです。Matrixオブジェクトはこのような応用で便利に使用できると思います。

諸元

  • Kaleidox : 0.1.9
気象データ

以下のページ「5.おもな都市の月平均気温・月降水量」のデータを使用しました。

http://www.biodic.go.jp/reports/2-2/hyo/aa126_001.html

2019年12月30日月曜日

Kaleidox: Table

前回はKaleidoxの中軸となるRecordオブジェクトについて説明しました。

今回はRecordオブジェクトと同様にKaleidoxの中軸オブジェクトであるTableオブジェクトについて説明します。

Tableオブジェクトは文字通り表を記述するオブジェクトで、Recordオブジェクトの列にスキーマとヘッダ、フッタの情報を加えたものになっています。

準備

Tableをデータベース入出力で使用するための環境としてKaleidoxの初期化ファイルinit.kldに以下の設定をします。

この設定をしておくと、H2データベースのメモリデータベース上にpersonテーブルが作成され、2レコードが格納された状態になります。

* env

db.default.driver="org.h2.Driver"
db.default.url="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false"

* voucher

** person

#+caption: 特性一覧
|特性  | 名前 | 型     | 多重度 | ラベル  |
|------+------+--------+--------+---------|
| 属性 | id   | int    |      1 | User ID |
| 属性 | name | string |      1 | 名前    |
| 属性 | city | string |      ? | 市      |

* data

** person

*** x

100,Taro,Yokohama
200,Hanako,Kawasaki

* main

store-create 'person
store-insert 'person x
DATA区画

準備として用意したinit.kldでは以下のデータ区画を定義しています。

* data

** person

*** x

100,Taro,Yokohama
200,Hanako,Kawasaki

変数xにCSVで記述された表データを持つTableオブジェクトが束縛されます。

入力

Tableオブジェクトの入力方法として以下の方法について見ていきます。

  • データベース読込み
  • CSVファイル
  • LTSVファイル
  • XMLファイル
  • JSONファイル
  • HTMLファイル
データベース読込み

Kaleidoxでは、データベースアクセスの仕組みとして以下の2つを用意しています。

Store
データストア機能
SQL
SQLで直接データベースアクセス
Store

データストア機能を使うと、スキーマ定義といったメタ情報を登録することで、データベースに対してレコードベースのインタフェースでアクセスすることができます。

データストアからstore-selectで検索すると、検索結果がテーブルを記述するTableオブジェクトに格納されて返されます。

以下ではstore-selectに検索条件を指定せずテーブル名のみを指定しているので全件検索になります。(ただし、読込件数はデフォルト値の件数で制限されます。)

kaleidox> store-select 'person
Table[3x2]

読み込んだTableの詳細情報を表示すると以下になります。

kaleidox> :show
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

Tableはオブジェクトなのでプロパティまたはメソッドを使って必要な情報を取り出すことができます。

以下headメソッドを使用して先頭の要素を取り出しています。

kaleidox> .head
id:100 name:Taro city:Yokohama
kaleidox> :show
Record[2] name:Taro city:Yokohama
SQL

データストア機能を使わず直接SQLを使用してデータベース内のデータをTableとRecordとして取得することもできます。

sql関数でSQL文を指定するとSQLが発行されます。SELECT文の場合は結果がTableとして返ってきます。

kaleidox> sql "select * from person"
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃ID │NAME│CITY    ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
kaleidox> .head
ID:100 NAME:Taro CITY:Yokohama
CSVファイル

CSVファイルからテーブルを読み込むことができます。

以下のCSVファイルpersons.csvを用意します。

id,name,city
100,Taro,Yokohama
200,Hanako,Kawasaki

CSVファイルの読込みにはtable-load関数を用います。table-load関数の引数にCSVファイルのURLを指定します。ローカルファイルでもHTTP経由でのリモートファイルでも読込み可能です。

kaleidox> table-load file:persons.csv
Tabble[3x2]

showコマンドで内容を表示すると以下のようにTableオブジェクトとして読み込まれています。

kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
LTSVファイル

LTSVファイルからテーブルを読み込むことができます。

以下のLTSVファイルpersons.ltsvを用意します。

id:100 name:Taro city:Yokohama
id:200 name:Hanako city:Kawasaki

LTSVファイルの読込みにはtable-load関数を用います。table-load関数の引数にLTSVファイルのURLを指定します。ローカルファイルでもHTTP経由でのリモートファイルでも読込み可能です。

kaleidox> table-load file:persons.ltsv
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
XMLファイル

XML文書から以下のいずれかの構造を読み取り、その情報に基づいてTableオブジェクトを生成することができます。

  • 表データ
  • レコードデータ
表データ

XML文書が以下のようにリスト構造になっている場合は表データとして解釈することができます。

<accounts>
  <account>
    <id>100</id>
    <name>Taro</name>
    <city>Yokohama</city>
  </account>
  <account>
    <id>200</id>
    <name>Hanako</name>
    <city>Kawasaki</city>
  </account>
</accounts>

table-make関数はXML文書の構造を解釈してTableオブジェクトとして読み込みます。

このXML文書をpersons.xmlとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

kaleidox> table-make file:persons.xml
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
レコードデータ

XML文書が以下のようにレコード構造になっている場合はレコードデータとして解釈することができます。

<account>
  <id>100</id>
  <name>Taro</name>
  <city>Yokohama</city>
</account>

このXML文書をperson.xmlとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

レコード構造の場合は1レコードを持つTableオブジェクトとなります。

kaleidox> table-make file:person.xml
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃id │name│city    ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
JSONファイル

JSON文書から以下のいずれかの構造を読み取り、その情報に基づいてTableオブジェクトを生成することができます。

  • 表データ
  • レコードデータ
表データ

JSON文書が以下のように配列になっている場合は表データとして解釈することができます。

[{
  "id": "100",
  "name": "Taro",
  "city": "Yokohama"
},{
  "id": "200",
  "name": "Hanako",
  "city": "Kawasaki"
}]

このJSON文書をpersons.jsonとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

kaleidox> table-make file:persons.json
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
レコードデータ

JSON文書が以下のようにレコード構造になっている場合はレコードデータとして解釈することができます。

{
  "id": "100",
  "name": "Taro",
  "city": "Yokohama"
}

このJSON文書をperson.jsonとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

レコード構造の場合は1レコードを持つTableオブジェクトとなります。

kaleidox> table-make file:person.json
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃id │name│city    ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
HTMLファイル

HTML文書からTableオブジェクトを生成することができます。この場合は、HTML文章内の表構造を抽出し、条件に適合するものをTableオブジェクトとして取り出します。

以下のHTMLファイルpersons.htmlにはtableタグによって表が1つ定義されています。

<html>
    <head>
<title>表サンプル</title>
    </head>
    <body>
<p>表のサンプルです</p>
<table>
   <thead>
<tr><th>id</th><th>name</th><th>city</th></tr>
   </thead>
   <tbody>
<tr><td>100</td><td>Taro</td><td>Yokohama</td></tr>
<tr><td>200</td><td>Hanako</td><td>Kawasaki</td></tr>
   </tbody>
</table>
    </body>
</html>

このHTMLファイルに対してtable-make関数を適用するとHTML文書内の表データをTableオブジェクトとして抽出することができました。

kaleidox> table-make file:persons.html
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

出力

データストア機能を使ってTableのデータをデータベースに格納することができます。

以下ではstore-insert関数を使って、personテーブルにTableの情報を追加しています。

kaleidox> store-insert x
(101)
kaleidox> store-get 'person 101
ID:101 NAME:Hanako CITY:Kawasaki
kaleidox> store-select 'person
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃101│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

参照

Tableの内容はRecordのシーケンスとして参照することができます。

準備

前述のinit.kldの設定によって、変数xにTableオブジェクトが束縛されています。

kaleidox> x
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

このTableオブジェクトを参照の対象にします。

プロパティ取得

Tableオブジェクトのプロパティは以下のようにプロパティ名を指定して取得することができます。

以下ではTableオブジェクトのカラム数をプロパティwidthで、レコード数をプロパティheightで取得しています。

kaleidox> x.width
3
kaleidox> x.height
2
レコード操作

Tableオブジェクトの先頭レコードはプロパティheadで取得することができます。

kaleidox> x.head
id:100 name:Taro city:Yokohama
kaleidox> :show
Record[3] id:100 name:Taro city:Yokohama

また、先頭レコードを除いた残りのレコードを保持したTableオブジェクトはプロパティtailで取得することができます。

kaleidox> x.tail
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

Tableオブジェクトが空の場合はプロパティheadはnilを返します。

kaleidox> setq y x.tail
Table[3x1]
kaleidox> y.tail
Table[3x0]
kaleidox> :show
Table[3x0]
┏━━┯━━━━┯━━━━┓
┃id│name│city┃
┣━━┿━━━━┿━━━━┫
┗━━┷━━━━┷━━━━┛
kaleidox> .head
nil
スキーマ

Tableオブジェクトのスキーマ情報はプロパティschemaで取得することができます。

kaleidox> x.schema
Schema[3] id,int,1 name,string,1 city,string,?
kaleidox> :show
Schema[3]
┏━━━━┯━━━━━━━━┯━━━━━━━━━━━━┓
┃name│datatype│multiplicity┃
┣━━━━┿━━━━━━━━┿━━━━━━━━━━━━┫
┃id  │int     │1           ┃
┃name│string  │1           ┃
┃city│string  │?           ┃
┗━━━━┷━━━━━━━━┷━━━━━━━━━━━━┛

まとめ

今回はKaleidoxの中軸オブジェクトの一つであるTableについて説明しました。

データベースやCSVファイルといった外部リソースの情報をTableオブジェクトとして読込み、Recordオブジェクト単位で処理していくのがKaleidoxの基本処理モデルです。TableとRecordをハブにして各種の連携を進めていきます。

諸元

  • Kaleidox : 0.1.8

2019年11月30日土曜日

Kaleidox: Record

Kaleidoxはレコードを記述するRecordというオブジェクトを提供しています。

RecordはKaleidoxの中軸となるオブジェクトで、データ処理を行う場合などRecordをハブにして様々な連携を行うようになっています。

今回はRecordの使い方について説明します。

準備

Recordをデータベース入出力で使用するための環境としてKaleidoxの初期化ファイルinit.kldに以下の設定をします。

この設定をしておくと、H2データベースのメモリデータベース上にpersonテーブルが作成され、1レコードが格納された状態になります。

* env

db.default.driver="org.h2.Driver"
db.default.url="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"

* voucher

** person

#+caption: 特性一覧
|特性  | 名前 | 型     | 多重度 | ラベル  |
|------+------+--------+--------+---------|
| 属性 | id   | int    |      1 | User ID |
| 属性 | name | string |      1 | 名前    |
| 属性 | city | string |      ? | 市      |

* main

store-create 'person
store-insert 'person id:100,name:Taro,city:Yokohama

入力

LXSVによるリテラル記述とデータベース読込みでRecordを作成することができます。

LXSV

LXSVリテラルによってRecordを作成することができます。

kaleidox> name:Taro,city:Yokohama
name:Taro city:Yokohama

showコマンドで内容を表示すると2つのプロパティを持つRecordであることが分かります。

kaleidox> :show
Record[2] name:Taro city:Yokohama
データベース読込み

Kaleidoxでは、データベースアクセスの仕組みとして以下の2つを用意しています。

Store
データストア機能
SQL
SQLで直接データベースアクセス
Store

データストア機能を使うと、スキーマ定義といったメタ情報を登録することで、データベースに対してレコードベースのインタフェースでアクセスすることができます。

store-get関数ではデータベースのテーブルからデータをRecordとして読み込むことができます。

以下ではpersonテーブルからID 100のRecordを取得しています。

kaleidox> store-get 'person 100
ID:100 NAME:Taro CITY:Yokohama

データストアからstore-selectでRecordを検索すると、検索結果がテーブルを記述するTableオブジェクトに格納されて返されます。

以下ではstore-selectに検索条件を指定せずテーブル名のみを指定しているので全件検索になります。(ただし、読込件数はデフォルト値の件数で制限されます。)

kaleidox> store-select 'person
Table[3x1]

読み込んだTableの詳細情報を表示すると以下になります。

kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃id │name│city    ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛

Tableはオブジェクトなのでプロパティまたはメソッドを使って必要な情報を取り出すことができます。

ここではheadメソッドを使用して先頭の要素を取り出しています。この先頭の要素は本記事のテーマであるRecordとして取り出されます。

kaleidox> .head
id:100 name:Taro city:Yokohama
kaleidox> :show
Record[2] name:Taro city:Yokohama
SQL

データストア機能を使わず直接SQLを使用してデータベース内のデータをTableとRecordとして取得することもできます。

sql関数でSQL文を指定するとSQLが発行されます。SELECT文の場合は結果がTableとして返ってきます。

前述したとおり、Tableオブジェクトのheadメソッドを呼び出すと先頭の行がRecordとして返ってきます。

kaleidox> sql "select * from person"
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃ID │NAME│CITY    ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
kaleidox> .head
ID:100 NAME:Taro CITY:Yokohama

出力

データストア機能を使ってRecordをデータベースに格納することができます。

以下ではstore-insert関数を使って、personテーブルにRecordを追加しています。

kaleidox> store-insert 'person id:101,name:Hanako,city:Kawasaki
(101)
kaleidox> store-get 'person 101
ID:101 NAME:Hanako CITY:Kawasaki
kaleidox> store-select 'person
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃101│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

参照

Recordの内容はプロパティとして参照することができます。

以下のように変数にpにRecordを束縛します。

kaleidox> setq p id:100,name:Taro,city:Yokohama
id:100 name:Taro city:Yokohama
プロパティ取得

プロパティ取得は以下のようにオブジェクトのプロパティを参照することで行なえます。

kaleidox> p.name
"Taro"
XPath

XPathを使ってRecordからプロパティ取得することもできます。

kaleidox> /name p
"Taro"

まとめ

今回はKaleidoxの中軸オブジェクトであるRecordについて説明しました。

次回はもう一つの中軸オブジェクトであるTableについて説明する予定です。

諸元

  • Kaleidox : 0.1.7

2019年10月31日木曜日

Kaleidox: LXSV

Kaleidoxはレコードを記述するRecordというデータ型を提供しています。

このRecordをテキストとして入出力するためのテキストフォーマットとしてLXSVを開発しました。LXSVを使うことでkaleidoxプログラム内でRecordをリテラルとして記述できます。

LXSVはLTSV(Labeled Tab-separeted Values)的なフォーマットを拡張したもので以下の特徴があります。

  • Kaleidoxプログラム内でリテラルとして記述可能
  • LTSVの概ね上位互換
  • 区切り記号を選択することができる

LXSVフォーマット

LXSVはUnicodeによるテキストフォーマットで区切り記号によってキーと値の対の列によるレコードと、改行コードで区切られたレコードの列を表現できます。

例えば以下のようなテキストがLXSVです。

name:Taro,city:Yokohama
name:Hanako,city:Kawasaki

このテキストではキーと値の対の区切り記号として「:」、キーと値の対の間の区切り記号として「,」を用いています。

キーと値の対の区切り記号は「:」固定ですが、キーと値の対の間の区切り記号は以下のルールによって決められます。

  • TAB、SPACE、「,」、「;」の中で最初に登場した文字を区切り記号とする。

このため以下のLXSVはすべて同じデータ構造を記述しています。

区切り記号: TAB

name:Taro city:Yokohama
name:Hanako city:Kawasaki

区切り記号: SPACE

name:Taro city:Yokohama
name:Hanako city:Kawasaki

区切り記号: ,

name:Taro,city:Yokohama
name:Hanako,city:Kawasaki

区切り記号: ;

name:Taro;city:Yokohama
name:Hanako;city:Kawasaki

区切り記号の入力

値の中にTAB, SPACE, 「,」, 「;」といった区切り記号を入れたい場合、以下の3つの方法があります。

  • 区切り記号の使い分け
  • 「"」で囲んで文字列として記述する。
区切り記号の使い分け

区切り記号を可変にしている理由の1つは区切り記号を値に入れたい場合の文字エスケープを回避することを可能にするためです。

name:Taro;city:Yokohama,Kawasaki
name:Hanako;city:Kawasaki,Yokohama

たとえば以下のように値の中に値の列を記述することも可能になります。ここではLXSVの区切り記号に「;」を使っています。そして、値の中の区切り記号に「,」を使っています。

name:Taro;city:Yokohama,Kawasaki
name:Hanako;city:Kawasaki,Yokohama
文字列

値の中にTAB, SPACE, 「,」, 「;」といった区切り記号を入れたい場合には、前述したように別の区切り記号を使うのが有効ですが、別の方法として「"」を使って文字列を指定することもできます。

name:Taro;city:"Yokohama,Kawasaki"
name:Hanako;city:"Kawasaki,Yokohama"

「"」を使って文字列を記述する場合は、「\n」や「\r」といったエスケープ文字を使って文字列に制御文字を入れることができます。また「”」の文字列内に「"」を入れる場合は「\"」として「\」を使ってエスケープします。

name:Taro;city:"Yokohama\nKawasaki"
name:Hanako;city:"Kawasaki\"Yokohama"

LXSVリテラル

Kaleidoxではレコードを記述するRecordというデータ型を提供しています。このRecordをリテラルとして記述する時にLXSVを用います。

kaleidox> name:Taro,city:Yokohama
name:Taro,city:Yokohama
kaleidox> :show
Record[2] name:Taro,city:Yokohama
文字列リテラルでの入力

Recordを文字列に対する修飾を使って入力することができます。文字列に対する修飾は文字列リテラルの前に修飾を示すプレフィックスを指定します。Recordの場合は「record」です。

以下のように使用します。

kaleidox> record"name:Taro,city:Yokohama"
name:Taro,city:Yokohama
kaleidox> :show
Reord[2] name:Taro,city:Yokohama

KaleidoxではLXSVのデータ型も用意されています。このデータ型を使う場合には修飾を示すプレフィックスとして「lxsv」を指定します。

kaleidox> lxsv"name:Taro,city:Yokohama"
name:Taro,city:Yokohama
kaleidox> :show
Lxsv[2] name:Taro,city:Yokohama

まとめ

Recordを使用するための前提となるLXSVについてご紹介しました。

次回はRecordの具体的な使い方について説明する予定です。

諸元

  • Kaleidox : 0.1.6

2019年9月30日月曜日

Kaleidox: JSON

Kaleidoxでは、実用的に利用できるアクション言語としてXML, HTML, JSON, CSV, Excelといったクラウドアプリケーションで使用する各種データ形式を簡単に扱えるようになっています。

前々回、前回とXMLとHTMLの操作方法について紹介しました。

今回はJSONの操作方法について紹介します。

JSONリテラル

例として以下のJSON文書を考えます。

また、このJSON文書を格納したJSONファイルをfile.jsonとして用意します。

{
  "id": "0001",
  "name": "taro",
  "point": 100
}
リテラル記述

KaleidoxではJSON文書をそのままリテラルとして記述することができます。

REPLでも以下のように直接入力することができます。

kaleidox> {
  "id": "0001",
  "name": "taro",
  "point": 100
}
{\n  "id": "0001",\n  "name": "taro",\n  "point": 100\n}
ファイル入力

REPLでJSON文書が格納されているJSONファイルからJSON文書を取り込む時は以下のようにJSONファイルのURLを記述すればOKです。

kaleidox> file:sample.json
{\n  "id": "0001",\n  "name": "taro",\n  "point": 100\n}\n

この例はプロトコルに「file」を指定してローカルファイルを読み込んでいますが、「http」を指定してリモートファイルを読み込むこともできます。

kaleidox> http://example.com/sample.json
{\n  "id": "0001",\n  "name": "taro",\n  "point": 100\n}\n

XPath

KaleidoxではJSON文書に対してXPathでパス検索をかけることができます。

{
  "id": "0001",
  "name": "taro",
  "point": 100
}

まずJSONファイルsample.jsonに対してXPath「@name」で検索すると以下になります。

JSON文書にある属性nameの値を取得することができました。

kaleidox> @name file:sample.json
"taro"

次にXPath「/name」で検索すると以下になります。こちらもJSON文書にある属性nameの値を取得することができました。

JSONにはXMLにある属性と要素の区別がないので、要素に対する検索ですがJSONの属性に対しても有効になっています。

kaleidox> /name file:sample.json
"taro"

XSLT

KaleidoxはJSON文書をXML文書にみたててXSLT変換を行うことができます。

サンプルとして使用しているJSON文書です。

{
  "id": "0001",
  "name": "taro",
  "point": 100
}

このJSON文書に対して提供するXSL記述は以下になります。

<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html"></xsl:output>

  <xsl:template match="/">
    <HTML>
    <BODY>
    <xsl:apply-templates/>
    </BODY>
    </HTML>
  </xsl:template> 

  <xsl:template match="record">
    <TABLE>
      <THEAD>
        <TR>
          <TH>ID</TH>
          <TH>Name</TH>
   <TH>Point</TH>
        </TR>
      </THEAD>
      <TBODY>
 <TR>
   <TD><xsl:value-of select="id"/></TD>
   <TD><xsl:value-of select="name"/></TD>
   <TD><xsl:value-of select="point"/></TD>
 </TR>
      </TBODY>
    </TABLE>
  </xsl:template> 
</xsl:stylesheet>

XMLやHTMLの場合と同様にXSLファイルに続けてJSONファイルを指定するとXSL変換が行われます。

kaleidox> file:sample.xsl file:sample.json
<HTML><BODY><TABLE><THEAD><TR><TH>ID</TH>
<TH>Name</TH><TH>Point</TH></TR>...

変換後のXML文書を詳細を表示すると以下になります。

無事XSLTでJSONファイルをHTML文書に変換することができました。

kaleidox> :show:print
<HTML><BODY><TABLE><THEAD><TR><TH>ID</TH>
<TH>Name</TH><TH>Point</TH></TR></THEAD>
<TBODY><TR><TD>0001</TD><TD>taro</TD>
<TD>100</TD></TR></TBODY></TABLE>
</BODY></HTML>

Table

XMLやHTMLと同様にJSON文書で記述した表情報をTableデータとして扱うことができます。

サンプルとして使用しているJSON文書です。

{
  "id": "0001",
  "name": "taro",
  "point": 100
}

このJSON文書に対してtable-make関数を適用します。

kaleidox> table-make file:sample.json
Table[3x1]

その結果、幅3、高さ1の表を得ることができました。

この表の内容をshowコマンドで表示すると以下になります。無事HTMLの表の内容を取得できています。

kaleidox> :show
Table[3x1]
┏━━━━┯━━━━┯━━━━━┓
┃id  │name│point┃
┣━━━━┿━━━━┿━━━━━┫
┃0001│taro│100  ┃
┗━━━━┷━━━━┷━━━━━┛

JSON文書がJson Objectの場合は1行のテーブルに変換されます。

レコードシーケンス

JSON文書がJson Objectの配列だった場合は配列の長さ分の行を持ったテーブルに変換されます。

まずJson Objectの配列を持ったJSON文書を用意します。

[{
  "id": "0001",
  "name": "taro",
  "point": 100
},{
  "id": "0002",
  "name": "hanako",
  "point": 200
}]

このJSON文書に対してtable-make関数を適用します。

kaleidox> table-make file:sample-table.json
Table[3x2]

その結果、幅3、高さ2の表を得ることができました。

この表の内容をshowコマンドで表示すると以下になります。無事HTMLの表の内容を取得できています。

kaleidox> :show:print
┏━━━━┯━━━━━━┯━━━━━┓
┃id  │name  │point┃
┣━━━━┿━━━━━━┿━━━━━┫
┃0001│taro  │100  ┃
┠────┼──────┼─────┨
┃0002│hanako│200  ┃
┗━━━━┷━━━━━━┷━━━━━┛

まとめ

今回はJSONの操作について説明しました。

JSONではXPath(パス検索)はXSLT(データ変換)といったXMLで用意されている便利な機能が基本機能として提供されていません。

KaleidoxではJSON文書をXML文書として操作可能にすることで、XMLの便利な機能をJSON文書にも適用できるようにしました。

前々回、前回、今回でXML、HTML、JSONの操作方法についてみてきました。

KaleidoxではXML、HTML、JSONについて詳細を意識することなくシームレスに操作することができることを確認できました。

次回はこのメカニズムの土台となっているRecordについてみていく予定です。

諸元

  • Kaleidox : 0.1.5