next up previous contents
Next: 1.5.3 マージャ Up: 1.5 プロセス・ネットワーク Previous: 1.5.1 フィルタ

1.5.2 ストリームの連結

また問題を少し変えて, こんどは与えられた数未満の自然数の平方と立方の両 方の総和を計算するプログラムを考えてみよう.

前節の場合と同様の方法で, 入力 n に対して を出力とするよう なフィルタを作るという方法はある. しかし, それではせっかく作った square 述語は使わずに, 別に定義しなければならない. そこで, 前述の square はそのままにして, 別に入力メッセージの立方を出力するようなフィ ルタを作って, これを使うことを考える.gif

このようなフィルタ自体をどう定義すれば良いかは, もうおわかりだろう.

cube([],Out) :- Out=[].
cube([One|Rest],Out) :-
    Cube:=One*One*One, Out=[Cube|OutTail], cube(Rest,OutTail).

このふたつのフィルタと残りの naturals, sum をどうストリームで結合する かだが, 入力には両方ともプロセス naturals の出力を共通に与えれば良い. これはごく簡単で

square_sum_up_to(N,Sum) :-
    naturals(N,Naturals), square(Naturals,Squares), cube(Naturals,Cubes),
    ...
と, 同じ変数を両方に書けば良い. 問題は Squares, Cubes の2本の出力スト リームに流れるメッセージすべてを, どうやってプロセス sum に渡すかであ る.

ひとつの方法は, まず片方のストリームのメッセージを送り込み, それが終っ たらもう一方のストリームのメッセージを送るようにすることである. その ための交通整理をする述語は以下のように書ける.

append([],In2,Out) :- Out=In2.
append([Msg|In1],In2,Out) :- Out=[Msg|OutTail], append(In1,In2,OutTail).
この述語は第1, 第2のふたつの引数が入力ストリームに, 第3引数が出力スト リームになっている. 全体としては, まず第1引数にやってくるメッセージを 次々に出力し, それが終ったら第2引数の方のメッセージを流すようにしてい る.

最初の節は, 第1引数である一方のストリームが終りまで来たら, 後は第2引数 であるもう一方のストリームをそのまままとめて出力ストリームとしてしまえ ば良い, という意味である. メッセージをひとつひとつ取り出しては中継す る必要はないわけである. もうひとつの節は, 第1引数のストリームの方にメッ セージが来たら, それをそのまま出力することを意味する.gif

この述語を使って全体のプログラムを書くと, 以下のようになる.

queer_sum(N,Sum) :-
    naturals(N,Naturals), square(Naturals,Squares), cube(Naturals,Cubes),
    append(Squares,Cubes,Both), sum(Both,Sum).

メッセージを交通整理する append では, メッセージの中身はまったく見てい ない. 単にメッセージが来たかどうかだけを見て, 来たメッセージをそのま ま中継しているだけである. そのため, どんなメッセージが流れるストリー ムに対しても, 同じ append を使うことができる. KL1 の変数に型がない (どんな型の値も入れられる) ことの利点が現れる例である.



next up previous contents
Next: 1.5.3 マージャ Up: 1.5 プロセス・ネットワーク Previous: 1.5.1 フィルタ



KLIC