第3章 練習問題 6-10

6 状態不変表明

P(R,Ys) = (Reverse(Xs) = R + Reverse(Ys))

ただし、ここで+はAppendを表す。

証明は必要かどうかわからないから、省略で。

7 別のappend関数

終了しない。

Msの初期値がnilでない場合、常に{Append Ls [Xs]}が呼ばれる。そのため終了しない。

8 反復的append

fun {Append Xs Ys}
   fun {Reverse R Xs}
      case Xs 
      of nil  then R
      [] X|Xr then {Reverse X|R Xr}
      end
   end

   fun {ReverseAppend R Xs}
      case Xs
      of nil  then R
      [] X|Xr then {ReverseAppend X|R Xr}
      end
   end
in
   {Reverse nil {ReverseAppend {Reverse nil Xs} Ys}}
end

9 反復計算とデータフロー変数

実際にデータフロー変数を使わずに、appendを定義することができた。

10 あるものがリストであるかどうかをチェックすること

変更すると{Leaf [1 2 3]}のようにリストを引数として与えるとブロックする。

2.8.2節において

内包チェック == (および、その逆の反駁チェック \= )は二引数の関数で、の等・不等が分かるまでブロックする。内包チェックも反駁チェックも束縛は行なわない。

とある。

そのため、X \= _|_はXがリストの場合、_|_の内容が分かるまでブロックする。次のように書きなおすとこのことがはっきりする。

fun {Leaf2 L}  X Xr in
   % XとXrが分かるまでブロックする
   L == X|Xr
end

11 差分リストの限界

ここで問題といわれているのは、

local X Y Z in
   local 
      D1 = (1|2|3|X)#X
      D2 = (4|5|6|Y)#Y
      D3 = (7|8|9|Z)#Z
   in
      {Show {AppendD D1 D2}}
      % (1)
      {Show {AppendD D1 D3}}
   end
end

という状況。

ここで、一度目のAppendD終了後(1の位置)でD1は(1|2|3|4|5|6|Y)#(4|5|6|Y)に束縛されている。
これを二度目のAppendDに渡すと、4|5|6|Yを7|8|9|Zで束縛しようとする。そのためエラーが発生する。

12 リストの平坦化の計算量

分からない。nとkが両方パラメータで、どう漸化式を解いたらいいか分からない。

直感によるとFlattenはO(n*n)でFlattenDはO(n)。

13 行列操作

転置と積だけ。

fun {Trans M}
   fun {Split Xs}
      case Xs
      of (Y|Yr)|Xr then 
	 Hs#Ts = {Split Xr}
      in
	 (Y|Hs)#(Yr|Ts)
      else nil#nil end
   end

   fun {Join Ys Xs}
      case Ys#Xs
      of (Y|Yr)#(X|Xr) then (Y|X)|{Join Yr Xr}
      else nil end
   end
in
   case M 
   of nil   then nil
   [] [[X]] then [[X]]
   [] (X|Xr)|Ys then
      Y#Yr = {Split Ys}
   in
      (X|Y)|{Join Xr {Trans Yr}}
   end
end

fun {Mul M1 M2}
   fun {Product Xs Ys}
      case Xs#Ys
      of (X|Xr)#(Y|Yr) then (X*Y)+{Product Xr Yr}
      else 0 end
   end

   M3 = {Trans M2}
in
   {Map M1 fun {$ X} 
	      {Map M3 fun {$ Y} {Product X Y} end}
	   end}
end

14 FIFOキュー

(a)

Xが未束縛のままになる。

(b)

キューに何かが挿入されている場合、SとEの等価性を判定するにはSとEが共に束縛されていなければならない。
しかし、Eは常に自由なので、ブロックしてしまう。

15 クイックソート

fun {QSort Xs}
   proc {QSortD Xs ?Y1 Y}
      case Xs
      of nil  then Y1 = Y
      [] X|Xr then
	 L1 = {Filter Xr fun {$ V} V <  X end}
	 L2 = {Filter Xr fun {$ V} V >= X end}
	 Z
      in
	 {QSortD L1 Y1 X|Z}
	 {QSortD L2 Z Y}
      end
   end
   Y1 
in
   {QSortD Xs Y1 nil}
   Y1
end

16 末尾再帰の畳み込み

fun {Zip Xs Ys}
   fun {Iter Xs Zs}
      case Xs
      of nil  then
	 Zs = Ys
	 nil
      [] X|Xr then Z in
	 (X#Z)|{Iter Xr Z|Zs}
      end
   end
in
   {Iter Xs nil}
end

(X#Z)|{Iter ...}は核言語に変換するときに、末尾再帰になるはず。
ヒントを正しく活用していない気がするが、単一化の特徴を使っているし、問題ないはず。

17 カリー化

gumpの使い方を調べるのが大変なので、後回し。