An Introduction to Guarded Horn Clauses

Preview:

DESCRIPTION

2007年頃のJavaEE勉強会で発表した「並行論理型言語GHCの紹介」の資料です。

Citation preview

An Introduction to

並行論理型言語GHCの紹介

【見覚え】小林浩一 (koichik) 【あります】

Agenda

論理型言語Prologの概要

並行論理型言語GHCの概要

GHCによる並行プログラミング

Prolog概要

1972年頃フランスで生まれる

一階述語論理のサブセット(ホーン論理)がベース

1980年代の人工知能ブームで注目

日本ではすっかり下火

ここ10年和書の新刊無し?

変数と定数

変数英大文字または_で始まる

_のみだと無名変数

ex) A, B, Foo

数値 ex) 1, 2, 3

文字列(シンボル)英小文字で始まるまたはシングルクオートで囲む

ex) a, bbb, hoge, 'XYZ'

単一化

A = B

変数Aと変数Bが「同じである」ことを示す

値が未定義の変数は一度だけ具体化できる

A = B

A = 5

B = 5

AとBは単一 (どちらも未定義)

Aと5は単一(Aは5に具体化)Bも5と単一 (Bも5に具体化)

Bは5と単一 (既に具体化済み)

リストの単一化

リスト

任意の長さを持つデータ構造

ex) [1, 2, 3] [] [H|T]

リストの単一化

長さが同じリストは単一化できる

同じ位置の要素同士が単一化される

[1, 2, 3] = [X, Y, Z]

[A, 2, 3] = [1, B|C]

Xは1,Yは2,Zは3

Aは1,Bは2,Cは[3]

複合項の単一化

複合項

名前と数の決まった引数を持つデータ構造

ex) point(10, 20)

複合項の単一化

名前と引数の数が同じ複合項は単一化できる

同じ位置の引数同士が単一化される

model(N, M) = model('EbiYuri', 'CanCam')

Prologプログラム

述語の集合

述語

ホーン節の集合

ホーン節

ヘッドとボディを持つ (ボディは省略可)

ボディはゴールの集合

H :- B1, B2, ・・・, Bn.

Prologプログラムの例

sum(1, 1).

sum(N, S) :-N1 is N - 1,sum(N1, S2),S is S2 + N.

節1(事実)

節2(規則)

述語

実行イメージ(1)

?- sum(2, S).

sum(1, 1).

単一化できない

処理系に質問する

1番目の節

実行イメージ(2)

?- sum(2, S).

sum(N, S).

単一化できる

処理系に質問する

Nは2に単一化SとSは単一化

2番目の節

実行イメージ(3)2番目の節

sum(N, S) :-N1 is N - 1,sum(N1, S2),

N=2

N1は1に単一化

sum(1, 1).

1番目の節単一化できる

S2は1に単一化

実行イメージ(4)2番目の節

sum(N, S) :-

N1 is N - 1,

sum(N1, S2),

S is S2 + N

Nは2に単一化

N1は1に単一化

S2は1に単一化

Sは3に単一化

実行イメージ(5)

?- sum(2, S).

sum(N, S).

単一化できる

処理系に質問する

Sは3に単一化

2番目の節

N=2,S=3

Prologの逐次性

ボディのゴール

記述順に実行する

述語が複数の節を持つ場合

記述順に試行する

H :- B1, B2, ・・・, Bn.

sum(1, 1).

sum(N, S) :-

Prologまとめ

Prologプログラムは述語の集合 述語は節の集合

節は一つのヘッドと任意のボディを持つ

単一化 A=B

AとBは「単一である」

述語の呼び出しも単一化で決まる

逐次性がある ボディのゴールは記述順に実行される

述語の節は記述順に試行される

Agenda

論理型言語Prologの概要

並行論理型言語GHCの概要

GHCによる並行プログラミング

GHC概要

Guarded Horn Clausesの略

上田和紀氏が考案

第五世代プロジェクト並列推論マシンPIMのOS (PIMOS) の記述言語KL1の土台となった

Prologがベース逐次性を排除

i.e. Prolog - 逐次性

「Prolog + 並行性」ではない!

逐次性の排除(1)

ボディの複数のゴール

並列に実行される

AND並列

H :- B1, B2, ・・・, Bn.

並列に実行

逐次性の排除(2)

述語の複数の節

並列に試行する

OR並列

sum(1, 1).

sum(N, S) :-並列に試行

AND並列

ex(A, B, C, D, E) :-X is A * B,Y is C * D,E is X + Y.

E = A * B + C * D

3つのゴールは並列実行される

ex(A, B, C, D, E) :-E is X + Y,X is A * B,Y is C * D.

記述順に意味なし並べ替えても同じ

OR並列

not(0, Out) :-Out = 1.

not(1, Out) :-Out = 0.

Out = !In

2つの節は並列に単一化を試みる

not(1, Out) :-Out = 0.

not(0, Out) :-Out = 1.

記述順に意味なし並べ替えても同じ

曖昧な節

sum(1, 1).

sum(N, S) :-N1 is N - 1,sum(N1, S2),S is S2 + N.

?- sum(1, S).

どちらの節も選択可能

(これはProlog)

非決定性

選択可能な節が複数ある場合どの節が選択されるかは非決定的

Non-determinism

Non-deterministic OR-parallel

選択した節が失敗(偽)した場合やり直さない

Committed Choice

Don't care non-determinism

ガード(1)

H :- G1, G2, …Gm | B1, B2, …Bn.

ヘッド

ボディガード

コミット演算子

ガード付きホーン節

ガード(2)

ガードが真となる節のみ選択される

複数の節のガードが真となる場合は?

一つの節だけが選択される

ボディが実行される節は一つだけ

選択は非決定的

節が排他的になるようガードを書くべき

Falt GHC

ガードゴールでは一部の組み込み述語しか利用できないGHCのサブセット

KL1のベース

ガード(3)

sum(1, S) :- true |S = 1.

sum(N, S) :- N>1 |N1 is N - 1,sum(N1, S2),S is S2 + N.

?- sum(1, S).

1番目の節が選択(記述順に依存しない)

AND並列の同期sum2(N, S) :-

sum(N, N1),sum(N1, S).

sum(N, N1) sum(N1, S)

sum2(N, S)

AND並列

依存関係

2つのゴールは並列に実行していいが…

OR並列の同期

sum(1, S) sum(N, S)

sum(N1, S)

OR並列

不確定

2つの節は並列に試行していいが…

sum(1, S) :- true |...

sum(N, S) :- N>1 |...

GHCの同期メカニズム

ガードによる同期

ガードは呼び出し側の変数を具体化できない

ボディでは可能

自分の変数は具体化できる

ガードの実行に必要な変数が具体化されるまで待機 (同期化) する

「単一化できる」or「単一化できない」が確定するまで待機 (サスペンド) する

他の節が選択されるまで待機 (サスペンド) する

GHCの同期(1)

sum(1, S) :- true |...

sum(N, S) :- N>1 |...

sum(N1, S)

OR並列

N1は具体化されてない

呼び出し側のN1を具体化できない

N(=N1)が具体化されないと

評価できない

N1が具体化されるまで

待機

GHCの同期(2)

sum(1, S) :- true |...

sum(N, S) :- N>1 |...

sum(N1, S)

OR並列

N1 = 2

呼び出し側のN1(=2)と1は

具体化できない

N(=N1=2)は1より大きい

右の節が選択され

ボディ実行

GHCの出力引数

sum(1, 1).

Prolog

sum(1, S) :- true |S = 1.

GHC

ヘッドで出力(第2引数)を単一化する

ボディで出力(第2引数)を単一化する

GHCまとめ

逐次性の排除 AND並列:ボディのゴールを並列に実行

OR並列 :複数の節を並列に試行

細粒度の並行性

ガードによる同期 ガードでは呼び出し側の変数を具体化できない

必要なら具体化されるまで待機

処理系 (KL1) KLIC

http://www.klic.org/index.ja.html

Agenda

論理型言語Prologの概要

並行論理型言語GHCの概要

GHCによる並行プログラミング

ジェネレータ

From~Toまでの数列 (リスト) を生成

gen(From, To, X) :- From =< To |X = [From|Xs],Next is From + 1,gen(Next, To, Xs).

gen(From, To, X) :- From > To |X = [].

ジェネレータ

gen(1, 2, X) X = [1 | Xs]

gen(2, 2, X) X = [2 | Xs]

gen(3, 2, X) X = []

X = [1, 2]結果

フィルタ

入力リストの要素を2倍にしたリストを出力

twice([X|Xs], Y) :- true |Y1 is X * 2,Y = [Y1|Ys],twice(Xs, Ys).

twice([], Y) :- true |Y = [].

フィルタ

twice([1,2], Y) Y = [2 | Ys]

twice([2], Y) Y = [4 | Ys]

twice([], Y) Y = []

Y = [2, 4]結果

パイプ&フィルタ

ジェネレータとフィルタを共有変数で連結

パイプライン並列 or ストリーム並列

pipe(From, To, Y) :- true |gen(From, To, X),twice(X, Y).

パイプ&フィルタ

gen(1, 2, X)

X = [1 | Xs]

gen(2, 2, X)

X = [2 | Xs]

gen(3, 2, X)

X = []

Y = [2, 4]

twice(X, Y)

Y = [2 | Ys]

twice(X, Y)

Y = [4 | Ys]

twice(X, Y)

Y = []

X = [1, 2] 結果

動的なプロセスネットワーク

エラストテネスのふるいによる素数の生成

primes(N, J) :- true |gen(2, N, I), sift(I, J).

sift([P|I], J) :- true |J = [P|L], filter(I, P, K), sift(K, L).

filter([N|I], P, K) :- N mod P =:= 0 |filter(I, P, K).

filter([N|I], P, K) :- N mod P =¥= 0 |K =[N|K1], filter(I, P, K1).

素数

primes

gen

sift

J =

素数

primes

gen

sift

2

J =

素数

primes

genfilter

2

2

sift sift

J =

3

素数

primes

genfilter

2

2

sift sift

J =

4

3

素数

primes

genfilter

2

2

sift sift

filter3

sift

3J =

4

5

素数

primes

genfilter

2

2

sift sift

filter3

sift

3J =

6 5

素数

primes

genfilter

2

2

sift sift

filter3

sift

3J =

7

5

6

素数

primes

genfilter

2

2

sift sift

filter3

sift

filter5

3 5J =

8 7

クイックソート

並列に適したアルゴリズム

quicksort(X, Y) :- true | qsort(X, Y, []).

qsort([X|Xs], Y, Z) :- true |partition(Xs, X, S, L),qsort(S, Y, [X|Ys]), qsort(L, Ys, Z).

qsort([], Y, Z) :- true | Y = Z.

partition([H|R], X, S, L) :- H =< X |S = [H|S1], partition(R, X, S1, L).

partition([H|R], X, S, L) :- H > X |L = [H|L1], partition(R, X, S, L1).

クイックソート

quicksort

qsort

partitionqsort qsort

partition

qsort qsort

partition

qsort qsort

高い独立性

アクタープログラミング

アクター?

任意の数のメッセージを受け取ることができる

任意の数のメッセージを送ることができる

GHCによるアクタープログラミング

アクター

メッセージの列を受け取る述語

メッセージの列

リスト

メッセージ

リストの要素

アクタープログラミング

アクターMsg

アクター

アクター

アクター

MsgMsg

概念 メッセージの列(リスト)

(本当はmerger必要)

アクタープログラミング

pingpong

hello

world

サンプル

pingpong

アクタープログラミング

pingpong(N) :- true |ping(N, [hello(X)|_]), pong([X|_]).

ping(N, [hello(Resp)|Msgs]) :- N > 0 |Resp = [world(Msgs)|_],N1 is N - 1, ping(N1, Msgs).

ping(0, [hello(Resp)|_]) :- true |Resp = [].

pong([world(Resp)|Msgs]) :- true |Resp = [hello(Msgs)|_],pong(Msgs).

pong([]).

要求駆動

必要とされた時に数列を生成

gen(From, [X|Xs]) :-true |

X = From,Next is From + 1gen(Next, Xs).

gen(_, []).

gen(1, X),...X = [N1|X1],...X1 = [N2|X2],...X2 = [],...

初期化

N1 = 1

N2 = 2

終了

GHCによる並行プログラミングまとめ

プロセスネットワークの構築

パイプ&フィルタ

動的な構築が可能

多様なプログラミングスタイル

アクタープログラミングはスタイルに過ぎない

オブジェクト指向もスタイルに過ぎない

遅延評価はスタイルに過ぎない

データ駆動 (先行評価的)

要求駆動 (遅延評価的)

実は低水準なプログラミング言語

参考文献

並列論理型言語GHCとその応用淵一博監修

古川康一・溝口文雄 共編

ISBN4-320-02266-1

並行論理プログラミング言語 GHC/KL1上田和紀

http://www.ueda.info.waseda.ac.jp/̃ueda/readings/GHC-intro.pdf