第5章 練習問題 2(b)-
2リフト制御システム (b)
制御装置を以下のように改造し、一度に移動するようにすればいい。
fun {Controller Init}
Tid = {Timer}
Cid = {NewPortObject Init
fun {$ state(Motor F Lid) Msg}
case Motor
of running then
case Msg
of stoptimer then
{Send Lid 'at'(F)}
state(stopped F Lid)
end
[] stopped then
case Msg
of step(Dest) then
if F == Dest then
state(stopped F Lid)
elseif F<Dest then
{Send Tid starttimer(5000*(Dest-F) Cid)} % ここ
state(running Dest Lid)
else % F>Dest
{Send Tid starttimer(5000*(F-Dest) Cid)} % ここ
state(running Dest Lid)
end
end
end
end}
in
Cid
end
3 リフト制御システムのフォールトトレランス
難しいので後回し。
4 終了検出
SubThreadを呼び出しが完了しても、ポートのストリーム上に1がSendされている保証がないため。
例えば、以下のようなコードがあったとする。そして、(*)の位置でが終了したとする。
declare SubThreda in
{NewThread proc {$}
{SubThread proc {$} <A> end}
{SubThread proc {$} <B> end}
% (*)
end ?SubThread}このとき、まだ<B>のスレッドが1つ存在するので、NewThreadは終了するべきではない。
しかし、(*)の位置に達した時に、ポートに1が送られていなかった場合、ポートのストリーム上の和は0になってしまう。
5 並列フィルタ
(a)
たいていの場合は、_。ただし、以下の6つの値が出現しうる。
- _
- 5|_
- 4|_
- 5|4|_
- [5 4]
- [4 5]
いくつかの値が出現し得るので、非決定性。
(b)
たいていの場合は、[5 4]。ただし、以下の5つの値が出現しうる。
- _
- 5|_
- 4|_
- 5|4|_
- [5 4]
- [4 5]
(c)
5|4|_もしくは4|5|_。
Aが束縛されると、[5 4 3]もしくは[4 5 3]になる。
(d)
FilterはO(n)。ConcFilterはO(1)。
そもそもConcFilterは再帰関数ではない。
Erlangのreceiveの意味
(a)
待ち時間が0なので、Cancelは直ちにunitに束縛される。
そのためWaitTwoの呼び出しは、{WaitTwo S unit}のようになる。WaitTwoは第一引数をひいきするので、これはSが束縛されているかのチェックとなる。そのため、この呼び出しは{IsDet S}と等価である。
よって待ち時間が0のとき、第2形式は第3形式と同じになる。
(b)
待ち時間が無限大なので、Cancelは決して束縛されない。
そのためWaitTwoの呼び出しは{Wait S}と等価になる。さらに、その後のcase S ofは、Sが束縛されるのを待つため、Waitを除去できる。
よって待ち時間が無限大のとき、第2形式は第1形式と同じになる。
(c)
T(recieve ... end Sin Sout) =
local
Name = {NewName}
thread {Delay T(Expr)} {Send Sin Name} end
fun {Loop S T#E Sout}
case S of M|S1 then
case M
of Name then E=S T(BodyT T Sout)
[] ....
end
end
end
T
in
{Loop Sin T#T Sout}
end一意なメッセージを生成するために{NewName}を使用した。また、この名前がelse節に捉えられないように、最初にタイムアウトのための節を挿入した。
本文中の翻訳と比較すると欠点が存在する。もし、メッセージが存在した場合、ストリーム上に余計なメッセージが挿入されてしまう。
7 制御抽象としてのErlangのreceive
あとでもう一度解く。
不明な点があるので、適当に。Mailbox.recieveはストリームを消費するが、それをどうするべきか?Erlangを再現するなら、メッセージを消すべきである。また本文の翻訳にのっとるなら、消費したストリームを返すべきである。
とりあえず、簡単に実装できる消費しないrecieveを実装した。
declare
fun {WaitTwo X Y}
{Record.waitOr X#Y}
end
% Mailbox.new
fun {NewMailBox} S P in
{NewPort S P}
S#P
end
% Mailbox.send
proc {SendMail _#P M}
{Send P M}
end
% Mailbox.recieve
fun {RecvMail S#_ L Time#F}
Cancel={Alarm Time}
fun {Case Msg L}
case L
of P#E|L2 then
if {P Msg} \= nil then
{E}
else
{Case Msg L2 Else}
end
end
end
fun {Loop S}
if {WaitTwo S Cancel}==1 then
case S of M|S1 then
{Case M L}
end
else E=S {F} end
end
T
in
{Loop S}
end
% ----------------
% テストコード
% ----------------
fun {Check Msg}
fun {P M} M==Msg end
fun {E} {Browse Msg} Msg end
in
P#E
end
fun {Id X} X end
MailBox = {NewMailBox}
{SendMail MailBox foo}
{Browse {RecvMail MailBox [{Check foo} {Check bar}] 1000#Id}}