作用型計算とその並列処理 米澤 明憲 2007 fall 式の参照透明性 • • 作用型の式は値を表示(denote)するもので、値の計算の方法 を指定しているものではない。 作用型の言語(ラムダ計算、ML,Scheme,….)おける式、また はその部分式は、参照透明性(referential transparency)を持 つ。 – 式の値は、その式に現れる部分式の値のみ依存す 合成性(compositionality) をもつ 複雑系でない!! – 同じ形(字面)を持つ式は、常に同じ値を持つ – 系: 同じ変数は常に同じ値を持つ 単一代入型言語 (single assignment) – 式は同じ値を持つ別の式で置き換えても、全体の値は変わ らない。 Program x x どのxも同 x じ値を持つ 参照透明性をもたない式・言語 • 命令型の言語(C, Fortran, Java, Pascal...) – x := x + 1 における x には参照透明性はない。 • ある種に様相論理: P、 Q – E.g., Pという述語が示す命題を 「知っている」という様相 命題をknow(P)という記法で表する。 するとknow(1=1) が真であるからといって、 参照透明性を用いてknow(明けの明星=金星) が真であることは証明できない。なぜなら、 1=1は真、かつ明けの明星=金星も真、真である後者の 命題をknow(…)の中に持ちこくと、必ずしも正しくない。 式のLazy/Eager Evaluation法 • • • • • Lazy評価=式の部分や関数の引数を実際に必要に なるまで、できるだけ評価しない。(逆がeager評価) Lazy評価Outermost/normal order reduction in λ計算 Lazy評価のほうが評価力が強い: first(x,y) = x, loop = tail loop answer = first(42, loop) 42 by lazy評価 未定義 by non-lazy評価 Strict関数:引数の一つでも未定義になると未定義! Strict Analysis: 関数がstrictかどうか定義プログラム を解析する。 クロージャの静的・動的束縛 • 関数 F x y = <body… x … z …x …y ..> 環境 • Fのクロージャ [F x y = <body… x … z …x …y ..>, ε] z=6 z=4 F x y = < ..x.. y..z…> F x y = < ..x.. y..z…> z=8 F 2 3 => ## zを6としてFを評価す るのが静的評価 F 2 3 => ?? zを8としてFを評価 するのが動的評価 どの時点の環境を埋め込んだクロージャ を用いて関数を評価するかの違い 遅延評価法(Delayed Evaluation) • 関数評価の際に、指定された引数の評価を 遅延して、その引数値が必要になるまで評 価しない、ことを遅延評価と呼ぶ。 • 目的: 不必要な評価を避ける。 • 記法: 例えば, del 記法で遅延評価する引 数で指定に付す。 f (g a) (del (h a)) • 実現法: del (h a) を評価するときhのクロー ジャを評価値とする。 call-by-name と call-by-need • call-by-nameは全ての関数呼び出しにおい てその全ての実引数が遅延評価される。 • call-by-needは一度評価した実引数の値は、 記録しておき、(call-by-nameにおいて)再 び本体現れた実引数の評価は、記録した 値しかしない。 無限リスト・・・遅延評価の応用 • int-list n = [n] ++ (int-list n+1) 例えばint-list[10]をeager評価すれば、直ぐ発散!そこで、 • d-int-list n = [n] ++ del (d-int-list n+1) とすると、必要なだけ長い整数のリストが得られる。実際、 • (d-int-list 1) ! 100 100 • (d-int-list 1) ! 1000 1000 となるはず。 “Cons should not evaluate its args”. • LISP, Scheme等にある関数 cons e1 e2 の 定義をはじめから con (del e1) (del e2) とみ なして実装すると、無限リストが扱える言語 ができる。 • 一般にデータ構造を新たに作る操作の実引 数の評価をすべて遅延評価にすると約束し ておくと、他の言語でも同様なことが可能に なる。これによって、無限に大きいデータ構 造が扱える。 • 課題: Schemeのinterpreterを改造し、無限リ ストが扱えるようにせよ。 作用型表現における並列処理 1. 2. 3. 4. 5. 全ての引数を並列に評価 Future構文を使う データフローによる並列処理 ペトリネット 通信するプロセスにネットワーク future構文-1• • • • • 作用型言語に並列処理構文を導入する一例 遅延評価の代りに並列評価: del からfutureへ cons (future (f a)) b において future (f a) の 評価値として即座にトークンを一つ発行する と同時に新しいプロセスを作り (f a) ,の評価を 開始させる。 (f a)の値が必要になり、かつまだ計算が終了 していなければ、必要とするプロセスは待機 状態にはいる。 (f a)の値が得られると、トークンとその値をす りかえ、待機していたプロセスは再開する。 future構文2 let x = cons (future e1) e2 in let y = (future e) in . . (f y) car x . end アクセスするプ ロセスは待機状 態に入る。 end 課題:Schemeにfuture機能を導入する実装せよ。 データフロー(Data Flow)計算モデル • • • • 1973, MIT のJ. Dennisによる。 プログラムは命令(インストラクション)の集合 各命令には入力データ(群)と出力データ(群) 命令は入力データ群がすべて揃うと発火・実行 • 入力データ群と出力データ群は結合し、リンクをなし、命令群は ノードとなって、全体としてグラフ構造をなす。 • 関数型の言語から、データフローグラフに変換されて実行する ことを想定されている。 ペトリネットモデル • データフローにおいて、データでなくトークンが流 れると見なすとわかりやすい。(歴史的にはデー タフローより古い。1960年台ドイツのPetriが使い はじめる。) • データの流れより、命令・行動群の同期の表現・ 解析に適している(使われことがある)。 • 有限・有向グラフで表現されサイクルがあってよ い。 • グラフのノードは2種類: 1. place -- 条件に対応し で表現。 2. transition -- 事象に対応し で表現 グラフ上の任意のパス上にはplaceとtransitionが必ず交互 の出現する。 系内のPlace上にどのようにトークンが配置されているかであ 系(システム)の状態をあらわす。 発火条件: 1つのtransitionの入力側アークにつながるす べてのplacesにトークンが存在するとき、そのtransitionは発 火し、入力側のplacesにある全てのトークンは、出力側の全 てのplacesに流れでる。 P-op開始 P-op終了 V-op開始 V-op終了 Semaphorによる同期 (有限長バッファの同期記述) Non-empty ⊃buffer contains empty slots Producer ready Consumer ready S1 M Buffer slot allocated Message placed in buffer slot S2 Message removed from buffer slot Buffer slot returned Non-empty ⊂buffer contains messages 2.2 Petri Net solution to the Message Buffer Problem Network of communicating processes -- stream-based programming -☆ cons の arg は全て lazy evaluation すると仮定 addl x = ((car x) + 1) : addl(cdr( x)) x : list (addl(x) ≡ cons(car(x) + 1, addl(cdr(x)))) “:”はcons operation x = [e1, e2, e3…….] addl x = [e1+l, e2+l, e3+l……] ☆ integers = l : (addl integers) l integers [1,2,3…] cons add1 x →はstream, はprocessと考えられる y cons(x.y) このnetworkの動作は次の2つの解釈ができる。 ① demand mode / demand-driven (要求駆動型) ② availability mode / data-driven (データ駆動型) ① lazy evaluation に対応 “integers”の場合 : integer ~ output stream から要求があるとまず、 consが出る。次に要求が来るとconsへ要求がゆき、これによって add1に要求が届き、から分かれた1がadd1への要求に応じて流れ 出る。 ◎このようなdemand-droverはData-flow graphの解釈に適用して もよい。 <“coroutine”とも解釈できる> ②addlもconsもindependentなプロセスでinputがあれば、どんどん 値を生成し考える。 addlist x y = ((hd x) + (hd y)); (addlist + (tl x)(tl y)) (addlist(x, y) ≡ cons(car(x) + car(y), addlist(cdr(x), cdr(y))) Hamming Problem 次のような性質を満たす数列を作り出す。 ① 1はその列に入っている。 ② もしxが列の中にあれば、その2x,3x,5xも列の中に入っている。 ③ ① ②以外の数は入っていない。 ④ 大きさの順になっている。(ascending order) これのためにmerger(x,y)を定義する。但しx,ytもに無限listの必要あり。 sums = 1 : (addlist integers sums) integers addlist 1 merger x y = if (car x) = (car y) then merger (car x) y else if (car x) < (car y) then (car x) : (merger (cdr x) y) else (car y) : (merger x (cdr y)) sums Merger x3 merger x2 x5 Hamming 問題の解法 l cons エラトセネス(Eratosthenes)のふるい * non trivial, 自明でない、なぜなら自分自身のcopyがnestingする。 * プロセスネットワークの図にかけない。 基本的方法 (1) 2よりはじまるintegersのlist : integer-from-2を用意 (2) integerのリストに対して小さい方から順にみてゆく。最初のマーク されていない要素は素数である。それをpと呼ぶ。 (3) それ以降のp番目ごとの数をマークする。(既にマークがあれば、無 視して) (4) (2)へ戻る filter(p,y) ≡ if(car (y) rem p) = 0 但しyはlist of int then filter(p,cdr(y)) else cons(car(y), filter(p,cdr(y))) Eratothenes篩 primes = sieve(integer-from-2) sieve (x ) = cons(car(x), sieve(filter((car x), cdr(x))) car(x) x cdr(x) filter car integer-from-2 cdr sieve primes
© Copyright 2024 ExpyDoc