第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 リフト制御システムのフォールトトレランス

難しいので後回し。

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