第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}}