Vocabulary. Mysterious, reserved, guarded, cautious SECRETIVE.
An Introduction to Guarded Horn Clauses
description
Transcript of An Introduction to Guarded Horn Clauses
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