ADP

Sun May 20 13:42:52 2012

facebook

twitter

開発者ブログ

SourceForge.JP

Loading

ADPとは

Another Data Processor の略で、主にデータ処理用の言語としてWEBプログラムやDBプログラムを作成する言語として開発しています。
軽量言語としてSQLとの親和性を高めたり、インストールが簡単に行えるようにデザインしています。
Prologをベースとしています。が、ユニフィケーションとバックトラックのみエッセンスとして使用しており、文法は独自のものを採用しています。
このWEBページもADPを使用したアプリケーション(CMS)で作成しています。

言語のコンセプト

ADPは以下のコンセプトを元に開発しています。
・軽量なスクリプト言語
・SQLとの親和性が高い言語を目指す
・動作に際して複雑なインストールを必要としない
・そこそこの実行速度
・シンプルかつ覚えやすい文法

追い込まれたエンジニアにとって頼りになる言語を目指す

5分でわかるADPの基本(構文の基礎)

文字列
文字列は以下のように指定します。
 " で文字列を囲むことによりC言語風に文字列を定義できます。
  →文字列の中に"を入れたい場合は、\"とする。
  →その他、\r,\n,\\に対応
 ' で文字列を囲むことによりBASIC言語風に文字列を定義できます。
  →文字列の中に'を入れたい場合は''と2回続ける
  *文字列を終了させずに改行を行った場合も、そのまま文字列として認識されます。
  つまり、
"SELECT * 
 FROM tab "
  は有効な文字列で、かつ改行もそのまま有効です。

変数
 $を頭につけた識別子が変数になります。

$x 
$value

述語(関数のようなもの)
述語は、ADPの評価単位になります。以下のように記述します。

 述語名引数リスト

print("Hello World")

文字列や数値、変数や述語を項といいます。

ゴール節(関数の本体部分のようなもの。実行単位)
項をカンマ(,)で区切ります。終わりは、セミコロン(;)になります。

,print("Hellow World");
ソースにゴール節を記述しますとそれが評価(実行)されます。
つまり、上記のコードは、有効なADPのソースで、adpコマンドにより実行されます。


ホーン節の定義(関数の定義のようなもの)
 以下のように+記号で開始し、ホーン節名と引数リストを記述し、つぎにゴール節を記述します。


 +ホーン節名引数リストゴール節


+horn_name($x,$y),print($x, '=', $y);


コメント
#以降、その行末まではがコメントになります。

,printn("Hello World"); # ここからコメントになります。


5分でわかるADPの動作(コード例)

Hellow Wold
・コード(helloworld.p)
,printn("Hello World.");
・実行例
D:\sample>adp helloworld.p
Hello World.
ADPは、プログラムを読み込みコンパイル後、ゴール節の評価(実行)を行います。
ゴール節は、,(カンマ)で始まり、項(実行単位)を評価(事項)し、;で終わります。
helloworldの例では、printn述語の評価を行っています。
printn述語は組み込み述語(ライブラリに相当)と呼ばれ、引数の項を画面に表示します。

式(四則演算)の例
・コード(expression.p)
,$x=10 ,$y=20  ,printn( $x + $y ); # 足し算
,$x=30 ,$y=40  ,printn( $x - $y ); # 引き算
,$x=50 ,$y=60  ,printn( $x * $y ); # 掛け算
,$x=70 ,$y=80  ,printn( $x / $y ); # 割り算
,$x=90 ,$y=100 ,printn( $x % $y ); # 剰余
・実行例
D:\sample>adp expression.p
30
-10
3000
0
90
ADPは、四則演算に対応しています。

ゴール節の評価(常にANDで行っている)
ゴール節の項は、コンマ , で区切られていますが、このコンマには AND の意味があります。
以下の例を見てみましょう。

・コード(condition.p)
,$x = 10 ,$y = 20 ,$x < $y ,printn("$x is smaller than $y."); # -- (1)
,$x = 10 ,$y = 20 ,$x > $y ,printn("$x is bigger than $y."); # -- (2)

・実行結果
D:\sample>adp condition.p
$x is smaller than $y.
(1)のprintnは実行されていますが、(2)のprintnは実行されていないことが解ります。
(2)の途中にあります。
$x > $y
は条件式になりますが、$xは10で$yは20になっていますので、評価は偽になります。
この場合、以降の処理には進みません。バックトラック(後述)されます。
ADP(Prolog)では、ゴール節の項はそれぞれ評価され、真であれば次の項の評価に移り、偽であれば次の評価は行われません(バックトラックされます)。

5分でわかるADPの制御構造(ユニフィケーション、バックトラック)

ホーン節とその評価(1)

ホーン節は、手続型の言語のサブルーチン(関数)のように使うこともできます。
後述するように機能的にはもっと複雑なことも出来ます。

以下の例では、$xと$yが与えられて、$zに$x*$x+$yを返す関数の例を示します。

・コード(func.p)
+func($x,$y,$z),$z = $x * $x + $y,!; #--(1)
,func(30,5,$z),print($z);

・実行結果
D:\sample>adp func.p
905

コードの(1)にあります +func ・・・の行がホーン節の定義になります。一行で終了していますが、ADPでは(Prologでも)、このようにシンプルに関数を書くことができます。
最後にあります ! はカットと言いまして後述するバックトラックに影響します。後程説明します。


ホーン節とその評価(2)ユニフィケーション

ADP(Prolog)のユニークな機能の一つユニフィケーションについて説明します。

先ずは例を見てみます。

・コード(unification.p)
+kencho('茨城県','水戸市');
+kencho('栃木県','宇都宮市');
+kencho('群馬県','前橋市');
+kencho('埼玉県','さいたま市');
+kencho('千葉県','千葉市');
+kencho('東京都','新宿区');
+kencho('神奈川県','横浜市');
,kencho('東京都',$x),printn($x);

・実行結果
D:\sample>adp unification.p
新宿区
ホーン節 kencho は、関東の都県の県庁所在地のDBになっています。
ゴール節では、
,kencho('東京都',$x)
という評価が行われています。
東京都の県庁所在地は新宿区と定義されていますが、実行結果を見ますとその通り'新宿区'が出力されています。

ADPにはこのようにホーン節と評価中の項(述語)のマッチングを行い、結果マッチするホーン節が見つかったら評価を真とします。
つまり、

,kencho('東京都',$x)

の評価では、ホーン節1つ1つとマッチングを行い、1つ目の引数が'東京都'である述語を検索することになります。unification.pのソースでは該当するホーン節がありますので、評価結果は真となります。
その時に、変数$xには、'新宿区'がマッチングされます。変数は、初期状態ではマッチングにおいて(なんでも良い)ということを示し、共に以降の評価においては、マッチングされた値を使用します。

,printn($x)

では、$xにマッチングされた、'新宿区'を出力することになります。

また、unification.pのコードにおいて、

,kencho('北海道',$x),printn($x)
としても、該当するホーン節が無い為、結果は何も表示されません。


ホーン節とその評価(3)バックトラック

ADP(Prolog)にはバックトラックと呼ばれる制御構造があります。
こちらも例を見てみます。このコートでは、全ての都県の県庁所在地が出力されます。

・コード(backtrack.p)
+kencho('茨城県','水戸市');
+kencho('栃木県','宇都宮市');
+kencho('群馬県','前橋市');
+kencho('埼玉県','さいたま市');
+kencho('千葉県','千葉市');
+kencho('東京都','新宿区');
+kencho('神奈川県','横浜市');
,kencho($x,$y),printn($x,":",$y),fail;

・実行結果
D:\sample>adp backtrack.p
茨城県:水戸市
栃木県:宇都宮市
群馬県:前橋市
埼玉県:さいたま市
千葉県:千葉市
東京都:新宿区
神奈川県:横浜市

ユニフィケーションの例との違いですが、都県の評価部分も変数になっています。

,kencho($x,$y)

上記の述語を評価しますと、全部のホーン節にマッチしますが、ADPでは先ずは先頭にあります、

+kencho('茨城県','水戸市');

にマッチして、先のprintn述語の評価を行います。その後、fail述語の評価を行いますが、fail述語は必ず評価に失敗します。
ADP(Prolog)では、述語の評価に失敗するとバックトラック(後戻り)を行います。
この例では、printn述語の再評価を行いますが、こちらも評価に失敗します。
次に、,kencho($x,$y)の再評価を行います。この再評価で、

+kencho('栃木県','宇都宮市');

にマッチし、再度printnの評価、failの評価、バックトラックと続き、結果としてkenchoの全てのホーン節とマッチします。最終的には全体がfailで終了します。
このようにADP(Prolog)ではバックトラックを使って全てのホーン節の評価を行うこともできます。


ホーン節とその評価(4)next述語(ADP独自の拡張)

バックトラックの例では、全てのホーン節kenchoの内容を出力するのにfail術語を使いましたが、fail述語では、評価に失敗するので全部のホーン節の内容を出力し終えた後は全体の評価も失敗します。
バックトラックを行いたいけど、全ての評価が終わった時は評価を続けたいということもあります。
next述語はそのような場合に使えます。以下再び例を見ています。


・コード(next.p)
+kencho('茨城県','水戸市');
+kencho('栃木県','宇都宮市');
+kencho('群馬県','前橋市');
+kencho('埼玉県','さいたま市');
+kencho('千葉県','千葉市');
+kencho('東京都','新宿区');
+kencho('神奈川県','横浜市');
,$c = 0 ,kencho($x,$y) ,printn($x,":",$y) ,$c = $c + 1 ,next ,printtn($c,"件");

・実行結果
D:\sample>adp next.p
茨城県:水戸市
栃木県:宇都宮市
群馬県:前橋市
埼玉県:さいたま市
千葉県:千葉市
東京都:新宿区
神奈川県:横浜市
7件

少し、プログラムが複雑になりましたが、$cでマッチした個数を数えながらnext述語でバックトラックを行い、全てのホーン節のマッチングが終了したら、next述語の次のprintn述語で、マッチした件数を出力しています。

このnext述語ですが、私が知る限り、ADPオリジナルの機能になります。next述語により非常にスッキリとループが書けます。
ホーン節とその評価(5) ! - カット述語
ルーターのパケットの許可、禁止ルールによくあるのですが、ルールを上から順に実行して、一致したらそれで評価終了ということがしたいことがあります。このような場合に、! カット述語を使います。


以下、年齢別の料金計算にカットを使ったコード例を示します。


・カットを使ったコード例(cut1.p)
+calc_age_price($age, $price, 0),       $age <  2, !;                        # -- (1)
+calc_age_price($age, $price, $result), $age < 12, $result = $price / 2, !;  # -- (2)
+calc_age_price($age, $price, $price);                                       # -- (3)

,calc_age_price(  0, 100, $result), printn("乳児料金:", $result), next; # 乳児料金を表示
,calc_age_price( 10, 100, $result), printn("子供料金:", $result), next; # 子供料金を表示
,calc_age_price( 20, 100, $result), printn("大人料金:", $result), next; # 大人料金を表示

・実行結果
D:\sample>adp cut.p
乳児料金:0
子供料金:50
大人料金:100

年齢別の料金が計算されています。よく見ると気づくかと思いますが、乳児の年齢は(2)の条件(12未満)に合致します。従いましてnext述語でバックトラックすると(2)も実行されますが、カット述語のおかげで(2)の評価は行われません。カット述語はこのようにホーン節に対して一度マッチしたものは二度とマッチさせないという機能があります。以下、カットを外した例を掲載ます。

・カットを使わないコード例(cut2.p)
+calc_age_price($age, $price, 0),       $age <  2;                        # -- (1)
+calc_age_price($age, $price, $result), $age < 12, $result = $price / 2;  # -- (2)
+calc_age_price($age, $price, $price);                                    # -- (3)

,calc_age_price(  0, 100, $result), printn("乳児料金:", $result), next; # 乳児料金を表示
,calc_age_price( 10, 100, $result), printn("子供料金:", $result), next; # 子供料金を表示
,calc_age_price( 20, 100, $result), printn("大人料金:", $result), next; # 大人料金を表示

・実行結果
D:\sample>adp cut2.p
乳児料金:0
乳児料金:50
乳児料金:100
子供料金:50
子供料金:100
大人料金:100

乳児料金が3回出てきています。カットを使わないで、乳児料金を正しく算出させる為には、子供料金と大人料金に正しく条件を入れます。(2)の子供料金の場合は、
$age >= 2, $age < 12
とし、(3)の大人料金の場合は、
$age >= 12
とします。


*ADPではこのように条件を手軽に記載できますが、バックトラックが発生した場合、ホーン節は出現順で評価されます。カットを使うと条件式を記載する手間が省けますが、評価順序を意識する必要があります。



Powered by ADP.