第二章 練習問題
核言語が初登場。書き直せという問題が多い。
1 自由変数と束縛変数
核言語へ変換すると以下のようになる。なので、第二のPの出現ではPは自由ではない。
local P in P = proc {$ X} if X > 0 then {P X-1} end end end
2 文脈的環境
問題の意図がよく掴めない。
とりあえず、呼び出し時に環境にNがない例。
local MulByN N in ... end {MulByN X Y}
次に3以外に束縛されている例。
local MulByN N in ... end local N in N = 42 {MulByN X Y} end
つまりこういう場合が存在するので、常にN->3を環境に追加する必要がある。
3 関数と手続き
次の関数Fは、返り値として何を持てばいいのが明かではないため、例外が発生する。
fun {F X} if false then X end end
しかし、手続きの場合返り値を持つ必要がないので、例外は発生しない。
4 if文とcase文
(a)
if <cond> then <then-c> else <else-c> end
は次のように書くことができる。
case <cond> of true then <then-c> else <else-c> end
(b)
case [0 1 2] of H|T then <s> end
を変換すると
declare local L H T in proc {Each F L} if L \= nil then H|T = L in {F H} {Each F T} end end L = [0 1 2] P = H|T if {Label L} == {Label P} andthen {Arity L} == {Arity P} then {Each proc {$ X} P.X=L.X end {Arity L}} {Show P} end end
となる。
核言語においてパターンは、lit(fet1:x1 ... fetN:xN)の形をしている?BNF的には違うが、意味はこれによって規定されている。
5 case文
せっかく書いたので貼っておく。コピペ用?
declare proc {Test X} case X of a|Z then {Show 'case'(1)} [] f(a) then {Show 'case'(2)} [] Y|Z andthen Y==Z then {Show 'case'(3)} [] Y|Z then {Show 'case'(4)} [] f(Y) then {Show 'case'(5)} else {Show 'case'(6)} end end {Test [b c a]} {Test f(b(3))} {Test f(a)} {Test f(a(3))} {Test f(d)} {Test [a b c]} {Test [c a b]} {Test a|a} {Test '|'(a b c)}
- {Test [b c a]}
- case(4)
- {Test f(b(3))}
- case(5)
- {Test f(a)}
- case(2)
- {Test f(a(3))}
- case(5)
- {Test f(d)}
- case(5)
- {Test [a b c]}
- case(1)
- {Test [c a b]}
- case(4)
- {Test a|a}
- case(1)
- {Test '|'(a b c)}
- case(6)
6 case文再訪
すべてcase
しかし、if文の場合f(X Y d) == f(a Y c)はfalseであることが分かるため、case(2)が出力される。
if f(X Y d) == f(a Y c) then {Show 'case'(1)} else {Show 'case'(2)} end
8 制御抽象
ありがちな問題。andalsoが短絡するか否か。
(a)
同じ結果になる。{AndAlso fun {$} true end fun{$}
(b)
fun {OrElse BP1 BP2} if {BP1} then true else {BP2} end end
9 末尾再帰
(a)
核言語へ展開する上で以下の2つの手続きを仮定する。
proc {Add X Y ?R} R=X+Y end proc {Eq X Y ?R} R=X==Y end
local Sum1 in local Sum2 in Sum1 = proc {$ N ?R} local EqR in {Eq N 0 EqR} if EqR then R=0 else local SumR in local AddR in {Add N ~1 AddR} {Sum1 AddR SumR} {Add N SumR R} end end end end end Sum2 = proc {$ N S ?R} local EqR in {Eq N 0 EqR} if EqR then R=S else local AddR1 in local AddR2 in {Add N ~1 AddR1} {Add N S AddR2} {Sum2 AddR1 AddR2 R} end end end end end end end
(b) Sum1
再帰呼び出し時のときの環境のみを追いかける。
N=10のとき
{Sum1 AddR SumR} | N:n0 R:r AddR:a0 SumR:s0 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域:n0=10 a0=9 r s0
N=9のとき
{Sum1 AddR SumR} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域:n0=10 n1=9 a0=9 a1=8 r s[0-1]
N=8のとき
{Sum1 AddR SumR} | N:n2 R:r AddR:a2 SumR:s2 |
{Add N SumR R} | N:n2 R:r AddR:a2 SumR:s2 |
{Add N SumR R} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域:n0=10 n1=9 n2=8 a0=9 a1=8 a2=7 r s[0-2]
N=7のとき
{Sum1 AddR SumR} | N:n3 R:r AddR:a3 SumR:s3 |
{Add N SumR R} | N:n3 R:r AddR:a3 SumR:s3 |
{Add N SumR R} | N:n2 R:r AddR:a2 SumR:s2 |
{Add N SumR R} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域: n0=10 n1=9 n2=8 n3=7 a0=9 a1=8 a2=7 a3=6 r s[0-3]
N=6のとき
{Sum1 AddR SumR} | N:n4 R:r AddR:a4 SumR:s4 |
{Add N SumR R} | N:n4 R:r AddR:a4 SumR:s4 |
{Add N SumR R} | N:n3 R:r AddR:a3 SumR:s3 |
{Add N SumR R} | N:n2 R:r AddR:a2 SumR:s2 |
{Add N SumR R} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域:n0=10 n1=9 n2=8 n3=7 n4=6 a0=9 a1=8 a2=7 a3=6 a4=5 r s[0-4]
N=5のとき
{Sum1 AddR SumR} | N:n5 R:r AddR:a5 SumR:s5 |
{Add N SumR R} | N:n5 R:r AddR:a5 SumR:s5 |
{Add N SumR R} | N:n4 R:r AddR:a4 SumR:s4 |
{Add N SumR R} | N:n3 R:r AddR:a3 SumR:s3 |
{Add N SumR R} | N:n2 R:r AddR:a2 SumR:s2 |
{Add N SumR R} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域: n0=10 n1=9 n2=8 n3=7 n4=6 n5=5 a0=9 a1=8 a2=7 a3=6 a4=5 a5=4 r s[0-5]
N=4のとき
{Sum1 AddR SumR} | N:n6 R:r AddR:a6 SumR:s6 |
{Add N SumR R} | N:n6 R:r AddR:a6 SumR:s6 |
{Add N SumR R} | N:n5 R:r AddR:a5 SumR:s5 |
{Add N SumR R} | N:n4 R:r AddR:a4 SumR:s4 |
{Add N SumR R} | N:n3 R:r AddR:a3 SumR:s3 |
{Add N SumR R} | N:n2 R:r AddR:a2 SumR:s2 |
{Add N SumR R} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域: n0=10 n1=9 n2=8 n3=7 n4=6 n5=5 n6=4 a0=9 a1=8 a2=7 a3=6 a4=5 a5=4 a6=3 r s[0-6]
N=3のとき
{Sum1 AddR SumR} | N:n7 R:r AddR:a7 SumR:s7 |
{Add N SumR R} | N:n7 R:r AddR:a7 SumR:s7 |
{Add N SumR R} | N:n6 R:r AddR:a6 SumR:s6 |
{Add N SumR R} | N:n5 R:r AddR:a5 SumR:s5 |
{Add N SumR R} | N:n4 R:r AddR:a4 SumR:s4 |
{Add N SumR R} | N:n3 R:r AddR:a3 SumR:s3 |
{Add N SumR R} | N:n2 R:r AddR:a2 SumR:s2 |
{Add N SumR R} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域: n0=10 n1=9 n2=8 n3=7 n4=6 n5=5 n6=4 n7=3 a0=9 a1=8 a2=7 a3=6 a4=5 a5=4 a6=3 a7=2 r s[0-7]
N=2のとき
{Sum1 AddR SumR} | N:n8 R:r AddR:a8 SumR:s8 |
{Add N SumR R} | N:n8 R:r AddR:a8 SumR:s8 |
{Add N SumR R} | N:n7 R:r AddR:a7 SumR:s7 |
{Add N SumR R} | N:n6 R:r AddR:a6 SumR:s6 |
{Add N SumR R} | N:n5 R:r AddR:a5 SumR:s5 |
{Add N SumR R} | N:n4 R:r AddR:a4 SumR:s4 |
{Add N SumR R} | N:n3 R:r AddR:a3 SumR:s3 |
{Add N SumR R} | N:n2 R:r AddR:a2 SumR:s2 |
{Add N SumR R} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域: n0=10 n1=9 n2=8 n3=7 n4=6 n5=5 n6=4 n7=3 n8=2 a0=9 a1=8 a2=7 a3=6 a4=5 a5=4 a6=3 a7=2 a8=1 r s[0-8]
N=1のとき
{Sum1 AddR SumR} | N:n9 R:r AddR:a9 SumR:s9 |
{Add N SumR R} | N:n9 R:r AddR:a9 SumR:s9 |
{Add N SumR R} | N:n8 R:r AddR:a8 SumR:s8 |
{Add N SumR R} | N:n7 R:r AddR:a7 SumR:s7 |
{Add N SumR R} | N:n6 R:r AddR:a6 SumR:s6 |
{Add N SumR R} | N:n5 R:r AddR:a5 SumR:s5 |
{Add N SumR R} | N:n4 R:r AddR:a4 SumR:s4 |
{Add N SumR R} | N:n3 R:r AddR:a3 SumR:s3 |
{Add N SumR R} | N:n2 R:r AddR:a2 SumR:s2 |
{Add N SumR R} | N:n1 R:r AddR:a1 SumR:s1 |
{Add N SumR R} | N:n0 R:r AddR:a0 SumR:s0 |
格納域: n0=10 n1=9 n2=8 n3=7 n4=6 n5=5 n6=4 n7=3 n8=2 n9=1 a0=9 a1=8 a2=7 a3=6 a4=5 a5=4 a6=3 a7=2 a8=1 a9=0 r s[0-8]
(b) Sum2
N=10のとき
{Sum2 AddR1 AddR2 R} | AddR1:a0 AddR2:b0 R:r |
格納域: a0:9 b0:10 r
N=9のとき
{Sum2 AddR1 AddR2 R} | AddR1:a1 AddR2:b1 R:r |
格納域: a0:9 a1:8 b0:10 b1:19 r
N=8のとき
{Sum2 AddR1 AddR2 R} | AddR1:a2 AddR2:b2 R:r |
格納域: a0:9 a1:8 a2:7 b0:10 b1:19 b2:27 r
N=7のとき
{Sum2 AddR1 AddR2 R} | AddR1:a3 AddR2:b3 R:r |
格納域: a0:9 a1:8 a2:7 a3:6 b0:10 b1:19 b2:27 b3:34 r
N=6のとき
{Sum2 AddR1 AddR2 R} | AddR1:a4 AddR2:b4 R:r |
格納域: a0:9 a1:8 a2:7 a3:6 a4:5 b0:10 b1:19 b2:27 b3:34 b4:40 r
N=5のとき
{Sum2 AddR1 AddR2 R} | AddR1:a5 AddR2:b5 R:r |
格納域: a0:9 a1:8 a2:7 a3:6 a4:5 a5:4 b0:10 b1:19 b2:27 b3:34 b4:40 b5:45 r
N=4のとき
{Sum2 AddR1 AddR2 R} | AddR1:a6 AddR2:b6 R:r |
格納域: a0:9 a1:8 a2:7 a3:6 a4:5 a5:3 a6:2 b0:10 b1:19 b2:27 b3:34 b4:40 b5:45 b6:49 r
N=3のとき
{Sum2 AddR1 AddR2 R} | AddR1:a7 AddR2:b7 R:r |
格納域: a0:9 a1:8 a2:7 a3:6 a4:5 a5:4 a6:3 a7:2 b0:10 b1:19 b2:27 b3:34 b4:40 b5:45 b6:49 b7:52 r
N=2のとき
{Sum2 AddR1 AddR2 R} | AddR1:a8 AddR2:b8 R:r |
格納域: a0:9 a1:8 a2:7 a3:6 a4:5 a5:4 a6:3 a7:2 a8:1 b0:10 b1:19 b2:27 b3:34 b4:40 b5:45 b6:49 b7:52 b8:54 r
N=1のとき
{Sum2 AddR1 AddR2 R} | AddR1:a9 AddR2:b9 R:r |
格納域: a0:9 a1:8 a2:7 a3:6 a4:5 a5:4 a6:3 a7:2 a8:1 a9:0 b0:10 b1:19 b2:27 b3:34 b4:40 b5:45 b6:49 b7:52 b8:54 b9:55 r
(c)
100,000,000ではどちらも終了しなかったんで、10,000,000でおこなった。
Sum1は終了しなかったが、Sum2は正しく計算した。
10 核言語への展開
declare local SMerge in SMerge = proc{$ Xs Ys R} case '#'(Xs Ys) of '#'(nil Ys) then R=Ys [] '#'(Xs nil) then R=Xs [] '#'(X|Xr Y|Yr) then if X =< Y then local Z Zr in R=Z|Zr Z=X {SMerge Xr Ys Zr} end else local Z Zr in R=Z|Zr Z=Y {SMerge Xs Yr Zr} end end end end end
11 相互再帰
N=0について、{IsEven 0}、{IsOdd 0}は共に一定の大きさのスタックで実行可能である。
次にN-1について{IsEven N-1}、{IsOdd N-1}が一定の大きさのスタックで実行可能であると仮定する。
すると{IsEven N}、{IsOdd N}は、{IsOdd N-1}、{IsEven N-1}のスタックの大きさで実行可能なので、一定の大きさのスタックで実行可能である。
よって非負の整数に対して{IsEven N}、{IsOdd N}が一定の大きさのスタックで実行可能である。
12 finnaly節を持つ例外
declare B X Y try <s1> catch X1 then B = true X = X1 end if B then <s2> raise X end end
13 単一化
まず、核言語へ変換する。
X = '|'(1:a 2:'|'(1:Z 2:nil)) % (1) Y = '|'(1:W 2:'|'(1:b 2:nil)) % (2) X = Y % (3)