<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>コンピューターの計算</title>
<link>https://ameblo.jp/i8am00/</link>
<atom:link href="https://rssblog.ameba.jp/i8am00/rss20.xml" rel="self" type="application/rss+xml" />
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com" />
<description>プログラミングの学習過程における感想や不満を書きなぐることにより、学習意欲の維持と自己顕示欲の充足とを図ることを目的とする。</description>
<language>ja</language>
<item>
<title>プログラミングinOCaml 練習問題3.5の答案と感想</title>
<description>
<![CDATA[ <h3>練習問題3.5</h3><p>　この問題は、練習問題3.4で定義したオブジェクトおよび擬似関数を用いて解く。それらの擬似関数などを以下に示す。</p><hr align="center" width="90%"><p>&nbsp;</p><h4>束縛</h4><p>　順序対(var, val)で表す。ここで、varは変数、valは値である。</p><p>&nbsp;</p><h4>部分環境</h4><p>　順序対(A, R)であり、[]による記法で表す。ここで、Aは同変数の束縛のクラス、RはA上の順序関係である。また、[]には宣言の新しい順に束縛が並ぶ。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px">例: x = 3, x =1の順で宣言がなされたときの変数xの部分環境<br><pr><code> [(x, 1), (x, 3)] </code></pr></div><p>&nbsp;</p><h4>環境(全体環境)</h4><p>　部分環境の和クラスであり、[]と⊕とによる記法で表す。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px">例: 変数xと変数yとが宣言された環境<br><pr><code> [(x, 1), (x, 3)]⊕[(y, 1)]</code></pr></div><p>&nbsp;</p><h4>宣言関数𝔇</h4><p>　環境Envと宣言による束縛のクラスとから新しい環境Env'を選ぶ。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env' = 𝔇(Env, {(var₀, val₀), ..., (varₙ, valₙ)})</code></pr></div><p>&nbsp;</p><h4>評価関数𝔈</h4><p>　式exprを環境Envで評価する。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>val = 𝔈(expr, Env)</code></pr></div><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="90%"><p>　以下の答案では、本問の2種類の宣言のうち、xとyとを同時に宣言するものを同時宣言と呼び、xを宣言した後にyを宣言するものを逐次宣言と呼ぶ。また、初期の大域環境Envを空[]とする。</p><p>&nbsp;</p><h5>同時宣言</h5><p>　同時宣言後の大域環境Envₚ'は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Envₚ' = 𝔇(Env, {(x, 𝔈(e₁, Env)), (y, 𝔈(e₂, Env))})<br>= {(x, 𝔈(e₁, Env)), (y, 𝔈(e₂, Env))} ⇢ []<br>= [(x, 𝔈(e₁, Env))] ⊕ [(y, 𝔈(e₂, Env))] </code></pr></div><p>となる。</p><p>&nbsp;</p><h5>逐次宣言</h5><p>　xについての宣言後の大域環境Envₛ'は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Envₛ' = 𝔇(Env, {(x, 𝔈(e₁, Env))})<br>= {(x, 𝔈(e₁, Env))} ⇢ []<br>= [(x, 𝔈(e₁, Env))]</code></pr></div><p>となり、yについての宣言後の大域環境Envₛ''は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Envₛ'' = 𝔇(Envₛ', {(y, 𝔈(e₂, Envₛ'))})<br>= 𝔇([(x, 𝔈(e₁, Env))], {(y, 𝔈(e₂, [(x, 𝔈(e₁, Env))]))})<br>= {(y, 𝔈(e₂, [(x, 𝔈(e₁, Env))]))} ⇢ [(x, 𝔈(e₁, Env))]<br>= [(x, 𝔈(e₁, Env))] ⊕ [(y, 𝔈(e₂, [(x, 𝔈(e₁, Env))]))] </code></pr></div><p>となる。</p><p>&nbsp;</p><p>　以上から相違点をまとめる。</p><div style="border:double 3px #c0c0c0;padding:5px;margin:10px;margin-left:10px;margin-right:10px"><pr><code> 答え:　同時宣言と逐次宣言とは、yに束縛される値が式e₂を評価したものである点は同じだが、その式e₂を評価する大域環境が異なる。<br>　より詳細には、同時宣言では初期の大域環境で式e₂が評価される。一方、逐次宣言では、変数xと式e₁の値との束縛が初期の大域環境に追加された大域環境で式e₂が評価される。 </code></pr></div><p>&nbsp;</p><hr align="center" width="90%"><p>&nbsp;</p><h3>感想</h3><h4>正解</h4><p>　どうにも正解の確信が持てずモヤモヤする。原因はlet定義にあるのだろう。</p><p>　いまさらだが、let定義は式ではない。式ではないのなら何なのだろう。テキストでは、OCamlのプログラムの実行とは、式を評価して値を求めることだ、との説明がなされていた。</p><p>　それならば式でないlet定義は、少なくとも"普通"のプログラムの実行ではなく、何か"特別"な動作なのだろうか。そういえば、let定義が対象とする大域環境も、OCamlでは明示的に扱えない。このあたりがモヤモヤの原因か。</p><p>　つまり、問題の2つのlet定義は違いがあるものの、その違いは外部には現れない。現れるのはプログラムが実行され、let定義されたyが評価されたときだが、そこまでは問題に含まれていない。なんのことはない、目に見える明確な違いを示してスッキリしたいのだが、それができないからモヤモヤしていただけか。</p><p>&nbsp;</p><h4>let定義</h4><p>　そもそもlet定義は必要なのだろうか。変数の定義は、let式があればこと足りるように思える。なぜなら、let定義だけ行うプログラムというのはありえない。必ずlet定義した変数を評価するはずだ。ならば、その評価のときにlet式を使えばよいのだ。もっといえば、プログラムの全部を1つの大きなlet式で覆ってしまえばよい。</p><p>　計算という点、OCamlでいうところの式の評価という点からは、let定義は不要に思える。必要となるのは、対話式のインターフェイスなどでだろう。let定義は、プログラマの便宜を図るために、実用性の観点から導入された仕組みなのだろうか。</p><p>　また、式の評価(値)が文脈に左右されるのはどうにも気持ちが悪い。例えば、関数fを、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>　let f x = (f x) + 1</code></pr></div><p>と定義した場合、再定義の回数によって、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>　f 0 = ?</code></pr></div><p>が異なる。これでは、対話式でうっかりミスして再定義した場合には、原因不明のバグに悩まされることになる。せめて、大域環境をダンプできればチェックのしようもあるのだが。</p><p>　とはいえ、この問題を解くまでは、何の疑問もなく使ってきた。気にしなければ、便利な仕組みなのだが。</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="80%"><p>&nbsp;</p><p><small>上記は、プログラミングinOCaml,五十嵐淳についての感想および練習問題の答案である。著作権を侵害してしまうことがないように問題文は載せていない。ただし、問題文中において、ごく短い文であって、ありふれた表現であり、それのみでは問題としての意味をなさないようなもの(例えば、"- - 1"など)は、著作物にあたらないと判断し、記述している。</small></p>
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12743799130.html</link>
<pubDate>Fri, 20 May 2022 12:00:00 +0900</pubDate>
</item>
<item>
<title>プログラミングinOCaml 練習問題3.4② ～③の答案</title>
<description>
<![CDATA[ <h3>練習問題3.4</h3><p>　②および③についても①と同様の解き方を用いる。</p><p>&nbsp;</p><hr align="center" width="90%"><p>&nbsp;</p><p>&nbsp;</p><p>　まずは、①で定義したオブジェクトおよび擬似関数を示す。</p><h4>束縛</h4><p>　順序対(var, val)で表す。ここで、varは変数、valは値である。</p><p>&nbsp;</p><h4>部分環境</h4><p>　順序対(A, R)であり、[]による記法で表す。ここで、Aは同変数の束縛のクラス、RはA上の順序関係である。また、[]には宣言の新しい順に束縛が並ぶ。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px">例: x = 3, x =1の順で宣言がなされたときの変数xの部分環境<br><pr><code> [(x, 1), (x, 3)] </code></pr></div><p>&nbsp;</p><h4><code>環境(全体環境)</code></h4><p><code>　部分環境の和クラスであり、[]と⊕とによる記法で表す。</code></p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px">例: 変数xと変数yとが宣言された環境<br><pr><code> [(x, 1), (x, 3)]⊕[(y, 1)]</code></pr></div><p>&nbsp;</p><h4><code>部分環境関数ℭ</code></h4><p><code>　変数varについての部分環境(A, R)を環境Envから抜き出す。</code></p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>(A, R) = ℭ(Env, var)</code></pr></div><p>&nbsp;</p><h4><code>参照関数ℜ</code></h4><p><code>　環境Envにおける変数varの参照。</code></p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>val = ℜ(Env, var)</code></pr></div><p>&nbsp;</p><h4><code>宣言関数𝔇</code></h4><p><code>　環境Envと宣言による束縛のクラスとから新しい環境Env'を選ぶ。</code></p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env' = 𝔇(Env, {(var₀, val₀), ..., (varₙ, valₙ)})</code></pr></div><p>&nbsp;</p><h4><code>評価関数𝔈</code></h4><p><code>　式exprを環境Envで評価する。</code></p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>val = 𝔈(expr, Env)</code></pr></div><h5>let式の書換え規則</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:10px;margin-right:10px"><pr><code>𝔈(let var₀ = expr₀ and ... and varₙ = exprₙ in expr, Env)<br>= 𝔈(expr, 𝔇(Env, {(var₀, 𝔈(expr₀, Env)), ..., (varₙ, 𝔈(exprₙ, Env))})</code></pr></div><h5>関数の書換え規則</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(f(x, y), Env) = f(𝔈(x, Env), 𝔈(y, Env))</code></pr></div><h5>変数の書換え規則</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(var, Env) = ℜ (Env, var)</code></pr></div><h5>定数の書換え規則</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(val, Env) = val</code></pr></div><p>&nbsp;</p><p>&nbsp;</p><p>　次に、これらの定義を用いた練習問題3.4②, ③の答案を示す。</p><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="90%"><p>&nbsp;</p><h3>②</h3><h4>式の書換え</h4><p>　初期の環境をEnv₀とする。②の式についての評価関数𝔈は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:10px"><pr><code>𝔈(let x = 2 and y = 3 in (let y = x and x = y + 2 in x * y) + y, Env₀)</code></pr></div><p>である。<code>Env₁ = 𝔇(Env₀, {(x, 𝔈(2, Env₀)), (y, 𝔈(3, Env₀))})</code>とおくと、let式の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 𝔈((let y = x and x = y + 2 in x * y) + y, Env₁)</code></pr></div><p>関数の書き換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 𝔈(let y = x and x = y + 2 in x * y, Env₁) + 𝔈(y,Env₁)</code></pr></div><p><code><code>Env₂ = 𝔇(Env₁, {(y, 𝔈(x, Env₁)), (x, 𝔈(y + 2, Env₁))})</code>とおくと、let式の書換え規則により、</code></p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><code><pr>= 𝔈(x * y, Env₂) + 𝔈(y, Env₁)</pr></code></div><p>関数の書き換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 𝔈(x, Env₂) * 𝔈(y, Env₂) + 𝔈(y, Env₁)</code></pr></div><p>変数の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = ℜ(x, Env₂) * ℜ(y, Env₂) + ℜ(y, Env₁)</code></pr></div><p>となる。</p><p>&nbsp;</p><h4>環境の導出</h4><h5>Env₀</h5><p>　Env₀は空とする。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₀ = []</code></pr></div><p>&nbsp;</p><h5>Env₁</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₁ = 𝔇(Env₀, {(x, 𝔈(2, Env₀)), (y, 𝔈(3, Env₀))})</code></pr></div><p>であり、<code>𝔈(2, Env₀) = 2</code>と<code>𝔈(3, Env₀) = 3</code>より、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= {(x, 2), (y, 3)} ⇢ []<br>= [(x,2)] ⊕ [(y, 3)]</code></pr></div><p>となる。</p><p>&nbsp;</p><h5>Env₂</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₂ = 𝔇(Env₁, {(y, 𝔈(x, Env₁)), (x, 𝔈(y + 2, Env₁))})</code></pr></div><p>であり、<code>𝔈(x, Env₁) = ℜ(x, Env₁) = 2と𝔈(y + 2, Env₁) = ℜ(y, Env₁) + 2 = 5</code> より</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = {(y, 2), (x, 5)} ⇢ [(x,2)] ⊕ [(y, 3)]<br>= [(x,5), (x,2)] ⊕ [(y, 2), (y, 3)] </code></pr></div><p>となる。</p><p>&nbsp;</p><h4>評価結果の予想</h4><p>　したがって、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> ℜ(y, Env₁) = 3<br>ℜ(x, Env₂) = 5<br>ℜ(y, Env₂) = 2</code></pr></div><p>である。</p><p>　よって、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:10px"><pr><code>𝔈(let x = 2 and y = 3 in (let y = x and x = y + 2 in x * y) + y, Env₀)<br>⋮<br>= ℜ(x, Env₂) * ℜ(y, Env₂) + ℜ(y, Env₁)<br>= 5 * 2 + 3<br>= 13</code></pr></div><p>となる。</p><p>&nbsp;</p><h4>変数の参照と宣言との対応</h4><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:10px"><pr><code> let x = 2 and y = 3 in (let y = <span style="font-weight:bold;">x</span> and x = <span style="font-weight:bold;">y</span> + 2 in <span style="font-weight:bold;">x</span> * <span style="font-weight:bold;">y</span>) + <span style="font-weight:bold;">y</span></code></pr></div><p>における変数参照は、y = x and x = y + 2のxおよびyと、x * yのxおよびyと、yである。</p><p>&nbsp;</p><h5>y = x and x = y + 2</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> 𝔈(let y = x and x = y + 2 in x * y, Env₁)</code></pr></div><p>より、xおよびyの変数参照が対象とする束縛は環境Env₁に属し、その環境Env₁は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₁ = 𝔇(Env₀, {(x, 𝔈(2, Env₀)), (y, 𝔈(3, Env₀))})</code></pr></div><p>である。</p><p>　したがって、xについての束縛は宣言x = 2によるものであり、y + 2についての束縛は宣言y = 3によるものである。</p><p>&nbsp;</p><h5>x * y</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> 𝔈(x * y, Env₂)</code></pr></div><p>より、xおよびyの変数参照が対象とする束縛は環境Env₂に属し、その環境Env₂は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₂ = 𝔇(Env₁, {(y, 𝔈(x, Env₁)), (x, 𝔈(y + 2, Env₁))})</code></pr></div><p>である。</p><p>　したがって、xについての束縛は宣言x = y + 2によるものであり、yについての束縛は宣言y = xによるものである。</p><p>&nbsp;</p><h5>y</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> 𝔈(y, Env₁)</code></pr></div><p>より、yの変数参照に対応する宣言は、上述したy + 2での宣言と同じものである。</p><p>　したがって、yについての束縛は宣言y = 3によるものである。</p><p>&nbsp;</p><p>&nbsp;</p><h4>まとめ</h4><div style="border:double 3px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:10px"><pr><code> 答え:　予想される評価結果は13である。<br>y = xにおけるxの参照は、宣言x = 2を指す。<br>x = y + 2におけるyの参照は、宣言y = 3を指す。<br>x * yにおけるxの参照は、宣言x = yを指す。<br>x * yにおけるyの参照は、宣言y = xを指す。<br>let ... yにおけるyの参照は、宣言y = 3を指す。<br>let <span style="background-color:#ffbfbf;">x =</span> 2 and <span style="background-color:#ffdfbf;">y =</span> 3 in (let <span style="background-color:#bfbfff;">y =</span> <span style="background-color:#ffbfbf;">x</span> and <span style="background-color:#bfe5d0;">x =</span> <span style="background-color:#ffdfbf;">y</span> + 2 in <span style="background-color:#bfe5d0;">x</span> *<span style="background-color:#bfbfff;"> y</span>) + <span style="background-color:#ffdfbf;">y</span></code></pr></div><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="90%"><p>&nbsp;</p><h3>③</h3><h4>式の書換え</h4><p>　初期の環境をEnv₀とする。③の式についての評価関数𝔈は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:0px;margin-right:0px"><pr><code> 𝔈(let x = 2 in let y = 3 in let y = x in let z = y + 2 in x * y * z, Env₀)</code></pr></div><p>である。<code>Env₁ = 𝔇(Env₀, {(x, 𝔈(2, Env₀))})</code>とおくと、let式の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:10px"><pr><code> = 𝔈(let y = 3 in let y = x in let z = y + 2 in x * y * z, Env₁)</code></pr></div><p><code>Env₂ = 𝔇(Env₁, {(y, 𝔈(3, Env₁))}) </code> とおくと、let式の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = 𝔈(let y = x in let z = y + 2 in x * y * z, Env₂)</code></pr></div><p><code>Env₃ = 𝔇(Env₂, {(y, 𝔈(x, Env₂))}) </code> とおくと、let式の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = 𝔈(let z = y + 2 in x * y * z, Env₃)</code></pr></div><p><code>Env₄ = 𝔇(Env₃, {(z, 𝔈(y + 2, Env₃))}) </code> とおくと、let式の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = 𝔈(x * y * z, Env₄)</code></pr></div><p>関数の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = 𝔈(x, Env₄) * 𝔈(y, Env₄) * 𝔈(z, Env₄)</code></pr></div><p>変数の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = ℜ(x, Env₄) * ℜ(y, Env₄) * ℜ(z, Env₄)</code></pr></div><p>となる。</p><p>&nbsp;</p><h4>環境の導出</h4><h5>Env₀</h5><p>　Env₀は空とする。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₀ = []</code></pr></div><p>&nbsp;</p><h5>Env₁</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₁ = 𝔇(Env₀, {(x, 𝔈(2, Env₀))})</code></pr></div><p>であり、𝔈(2, Env₀) = 2より、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = {(x, 2)} ⇢ []<br>= [(x, 2)]</code></pr></div><p>となる。</p><p>&nbsp;</p><h5>Env₂</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₂ = 𝔇(Env₁, {(y, 𝔈(3, Env₁))})</code></pr></div><p>であり、𝔈(3, Env₁) = 3より、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = {(y, 3)} ⇢ [(x, 2)]<br>= [(x, 2)] ⊕ [(y, 3)]</code></pr></div><p>となる。</p><p>&nbsp;</p><h5>Env₃</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₃ = 𝔇(Env₂, {(y, 𝔈(x, Env₂))})</code></pr></div><p>であり、𝔈(x, Env₂) = ℜ(x, Env₂) = 2より、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = {(y, 2)} ⇢ [(x, 2)] ⊕ [(y, 3)]<br>= [(x, 2)] ⊕ [(y, 2), (y, 3)]</code></pr></div><p>となる。</p><p>&nbsp;</p><h5>Env₄</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₄ = 𝔇(Env₃, {(z, 𝔈(y + 2, Env₃))})</code></pr></div><p>であり、𝔈(y + 2, Env₃) = ℜ(y, Env₃) + 2 = 2 + 2 = 4より、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> = {(z, 4)} ⇢ [(x, 2)] ⊕ [(y, 2), (y, 3)]<br>= [(x, 2)] ⊕ [(y, 2), (y, 3)] ⊕ [(z, 4)]</code></pr></div><p>となる。</p><p>&nbsp;</p><h4>評価結果の予想</h4><p>　したがって、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> ℜ(x, Env₄) = 2<br>ℜ(y, Env₄) = 2<br>ℜ(z, Env₄) = 4</code></pr></div><p>である。</p><p>　よって、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:0px;margin-right:0px"><pr><code> 𝔈(let x = 2 in let y = 3 in let y = x in let z = y + 2 in x * y * z, Env₀)<br>⋮<br>= ℜ(x, Env₄) * ℜ(y, Env₄) * ℜ(z, Env₄)<br>= 2 * 2 * 4 = 16</code></pr></div><p>となる。</p><p>&nbsp;</p><h4>変数の参照と宣言との対応</h4><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:10px"><pr><code> let x = 2 in let y = 3 in let y = <span style="font-weight:bold;">x</span> in let z = <span style="font-weight:bold;">y</span> + 2 in <span style="font-weight:bold;">x</span> * <span style="font-weight:bold;">y</span> * <span style="font-weight:bold;">z</span></code></pr></div><p>における変数参照は、y = xのxと、z = y + 2のyと、 x * y * zのx, y, およびzである。</p><p>&nbsp;</p><h5>y = x</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> 𝔈(let y = x in let z = y + 2 in x * y * z, Env₂)</code></pr></div><p>より、xの変数参照が対象とする束縛はEnv₂に属し、そのEnv₂は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₂ = 𝔇(Env₁, {(y, 𝔈(3, Env₁))})</code></pr></div><p>である。Env₂の宣言関数𝔇はxについての束縛を含まないので、Env₂におけるxの束縛のクラスはEnv₁のものと同一とである。そのEnv₁は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₁ = 𝔇(Env₀, {(x, 𝔈(2, Env₀))})</code></pr></div><p>であるので、xについての束縛は宣言x = 2によるものである。</p><p>&nbsp;</p><h5>z = y + 2</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> 𝔈(let z = y + 2 in x * y * z, Env₃)</code></pr></div><p>より、yの変数参照が対象とする束縛はEnv₃に属し、そのEnv₃は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₃ = 𝔇(Env₂, {(y, 𝔈(x, Env₂))})</code></pr></div><p>であるので、yについての束縛は宣言y = xによるものである。</p><p>&nbsp;</p><h5>x * y * zのx</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> 𝔈(x * y * z, Env₄)</code></pr></div><p>より、xの変数参照が対象とする束縛はEnv₄に属し、そのEnv₄は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₄ = 𝔇(Env₃, {(z, 𝔈(y + 2, Env₃))})</code></pr></div><p>であるが、Env₄の宣言関数𝔇はxの束縛を含まず、さらに、Env₃についても、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₃ = 𝔇(Env₂, {(y, 𝔈(x, Env₂))})</code></pr></div><p>より、Env₃の宣言関数𝔇はxの束縛を含まない。これより、Env₄およびEnv₃におけるxの束縛のクラスはEnv₂のもの同一となる。</p><p>　したがって、x * y * zにおけるxの変数参照に対応する宣言は、上述したy = xでの宣言と同じとなる。よって、xについての束縛は宣言x = 2によるものである。</p><p>&nbsp;</p><h5>x * y * zのy</h5><p>　Env₄の宣言関数𝔇はyの束縛を含まないので、yの束縛のクラスはEnv₃のものと同一である。</p><p>　したがって、上述したように、yについての束縛は宣言y = xによるものである。</p><p>&nbsp;</p><h5>x * y * zのz</h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> Env₄ = 𝔇(Env₃, {(z, 𝔈(y + 2, Env₃))})</code></pr></div><p>より、zについての束縛は宣言z = y + 2によるものである。</p><p>&nbsp;</p><h4>まとめ</h4><div style="border:double 3px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:10px"><pr><code> 答え:　予想される評価結果は16である。<br>y = xにおけるxの参照は、宣言x = 2を指す。<br>z = y + 2におけるyの参照は、宣言y = xを指す。<br>x * y * zにおけるxの参照は、宣言x = 2を指す。<br>x * y * zにおけるyの参照は、宣言y = xを指す。<br>x * y * zにおけるzの参照は、宣言z = y + 2を指す。<br>let <span style="background-color:#ffbfbf;">x =</span> 2 in let y = 3 in let <span style="background-color:#fff3c3;">y =</span> <span style="background-color:#ffbfbf;">x</span> in let <span style="background-color:#bfe5d0;">z =</span> <span style="background-color:#fff3c3;">y</span> + 2 in <span style="background-color:#ffbfbf;">x</span> * <span style="background-color:#fff3c3;">y</span> * <span style="background-color:#bfe5d0;">z</span></code></pr></div><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="80%"><p>&nbsp;</p><p><small>上記は、プログラミングinOCaml,五十嵐淳についての感想および練習問題の答案である。著作権を侵害してしまうことがないように問題文は載せていない。ただし、問題文中において、ごく短い文であって、ありふれた表現であり、それのみでは問題としての意味をなさないようなもの(例えば、"- - 1"など)は、著作物にあたらないと判断し、記述している。</small></p>
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12743798239.html</link>
<pubDate>Fri, 20 May 2022 12:00:00 +0900</pubDate>
</item>
<item>
<title>プログラミングinOCaml 練習問題3.4①の答案</title>
<description>
<![CDATA[ <h3>練習問題3.4</h3><p>　本問では、OCamlによる式の評価結果を予想しなければならない。その予想を合理的に行うためには、評価の手順を形式的に記述していく必要があるだろう。</p><p>　本問を解くにあたり重要となるのは、式の評価そのものではなく、式に含まれるlet式による変数の宣言や、その変数の参照である。</p><p>　そこで、let式に関連するオブジェクトとして束縛や環境などを定義し、それにより変数の宣言、参照などを擬似的な関数として表現することを考える。</p><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="30%"><h4>束縛</h4><p>　束縛は、変数varと値valとの順序対(var, val)とする。束縛の全体クラス（以下、束縛クラス𝔅という）は、変数の全体クラス𝖀と値の全体クラス𝖁との直積になる。</p><p>&nbsp;</p><h4>環境</h4><p>　テキストでは、すべての束縛を1つにまとめて環境としていたが、この答案では、変数ごとに環境(部分環境)を定め、その部分環境を集めて全体の環境(全体環境)を定めることにする。</p><h5>&nbsp;</h5><h5>変数ごとの部分環境</h5><p>　部分環境は、同じ変数の束縛を集め、その集まりを宣言の新しい順番に並べて定められる。例えば、変数xについての宣言が、順に、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> let x = 1<br>let x = 5<br>let x = 2</code></pr></div><p>とされた場合、変数xについての部分環境を、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> [(x, 2), (x, 5), (x, 1)]</code></pr></div><p>と定める。このような定義が可能である根拠について述べる。</p><p>　変数の宣言がなされると、その宣言での変数と値とで束縛が定まる。なされたすべて宣言に対し、宣言ごとに束縛が一意的に定まるので、それらの束縛からなるクラスが、束縛クラス𝔅の部分クラスとしてとれる。</p><p>　その部分クラスのさらなる部分クラスとして、宣言された変数aに対し、同じ変数aを持つ束縛のクラス(同変数クラスと呼ぶ)Aがとれる(つまり、はじめの部分クラスは宣言された全ての変数の束縛を含み、同変数クラスは変数aの束縛のみを含む)。</p><p>　また、その同変数クラスAの冪クラスの部分クラスで、同変数クラスAを線形順序づけ、かつその順序づけが、新しい宣言の束縛ほど小さくなるような順序づけである順序関係Rがとれる。</p><p>　それら同変数クラスAと順序関係Rとの順序対(A, R)により変数aの部分環境が定められる。</p><p>　さらに、部分環境の略記のために、同変数クラスAの要素を順序関係Rの昇べき順に並べた記法[]を導入する。例えば、束縛a, b, cを要素とする同変数クラスAと順序関係Rとが、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> A = {a, b, c}<br>R = {(c, a), (c, b), (b, a)}</code></pr></div><p>であるとき、[]による記法は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>[c, b, a]</code></pr></div><p>となる。この記法では、[]における最も左側の要素が、最も新しい宣言による束縛であり、変数参照される束縛になる。</p><p>　また、部分環境では、変数参照による値が一意的に定まるが、これは、順序関係Rが同変数クラスAを整列順序づけることと同値である。</p><p>&nbsp;</p><h5>全体環境</h5><p>　全体環境は、すべての変数についての部分環境の集まり、つまり順序対(A, R)の和クラスとなる。</p><p>　全体環境の略記として、部分環境の要素を合わせる記法⊕を導入する。例えば、変数xの部分環境と変数yの部分環境とを集めた全体環境は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>[(x, 1), (x, 3)...]⊕[(y, 1)]</code></pr></div><p>と表される。以下、全体環境を単に環境という。</p><p>&nbsp;</p><p>&nbsp;</p><p>　以上のオブジェクトを用いて、変数の参照、宣言と式の評価とを擬似的な関数として定義する。擬似的というのはOCamlの関数ではないという意味である。</p><hr><p>&nbsp;</p><h4>部分環境の取出し関数</h4><p>　環境Envから変数varの部分環境(A, R)を取り出す関数ℭを、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>ℭ = {((Env, var), (A, R)) |<br>&nbsp;&nbsp; A ⊂ {var} × 𝖁<br>&nbsp;&nbsp; ∧ ((A ≠ ∅ ∧ R ⊂ 𝒫(A) ∧ (A, R) ⊂ Env)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ∨ (A = ∅ ∧ (A, R) = (∅, ∅))}</code></pr></div><p>と定義する。関数ℭは、引数として環境Envと変数varとを受け取り、部分環境をなす順序対(A, R)を値に返す。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>(A, R) = ℭ(Env, var)</code></pr></div><p>&nbsp;</p><h4>参照関数</h4><p>　変数参照を擬似的な関数ℜとする。この参照関数ℜは、引数として環境Envと変数varとを受け取り、そのvarに束縛された値valを返す。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>val = ℜ (Env, var)</code></pr></div><p>より詳細には、参照関数ℜは、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>ℜ = {((Env, var), val) |<br>&nbsp;&nbsp; (A, R) = ℭ(Env, var)<br>&nbsp;&nbsp; ∧ (var, val) ∈ A<br>&nbsp;&nbsp; ∧ ∀a((a ∈ A ∧ a ≠ (var, val)) → (var, val) R a)}</code></pr></div><p>で定義される。</p><p>&nbsp;</p><h4>宣言関数</h4><p>　変数の宣言を擬似的な関数𝔇とする。この宣言関数𝔇は、引数として環境Envと束縛のクラスBとを受け取り、値として新たな環境Env'を返す。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env' = 𝔇(Env, B)</code></pr></div><p>　宣言var₀ = val₀ and ... and&nbsp; varₙ = valₙにより束縛のクラスB = {(var₀, val₀), ..., (varₙ, valₙ)}が定まるとき、宣言関数𝔇を、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env' = {(var</code>₀<code>, val</code>₀<code>), ..., (var</code>ₙ<code>, val</code>ₙ<code>)} ⇢ Env</code></pr></div><p>とも表すことにする。</p><p>　宣言関数𝔇の詳細な定義は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔇 = {((Env, B), Env') |<br>&nbsp;&nbsp; (var, val) ∈ B<br>&nbsp;&nbsp; ∧ (A, R) = ℭ(Env, var)<br>&nbsp;&nbsp; ∧ A' = {(var, val)} ∪ A<br>&nbsp;&nbsp; ∧ R' =&nbsp; {(x, y) | x = (var, val) ∧ y ∈ A} ∪ R<br>&nbsp;&nbsp; ∧ Env' = {(A', R')} ∪ Env}</code></pr></div><p>である。</p><p>&nbsp;</p><h4>評価関数</h4><p>　式の評価を擬似的な関数𝔈とする。この評価関数𝔈は、式exprと環境Envとを引数として受け取り、値valを返す。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>val = 𝔈(expr, Env)</code></pr></div><p>この評価関数𝔈の性質を考える。</p><p>&nbsp;</p><h5>let式の書換え規則</h5><p>　let式は、inの前での変数宣言による新たな環境で、inの後の式を評価する。つまり、let式を含む評価関数𝔈は、宣言関数𝔇と評価関数𝔈とにより、let式を含まない式に書換えられる。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(let var₀ = expr₀ and ... and varₙ = exprₙ in expr, Env)<br>= 𝔈(expr, 𝔇(Env, {(var₀, 𝔈(expr₀, Env)), ..., (varₙ, 𝔈(exprₙ, Env))})</code></pr></div><p>&nbsp;</p><h5>関数の書換え規則</h5><p>　OCamlは、静的有効範囲を採っているので関数(四則演算など)の動作は、呼び出し時の環境によらない。</p><p>　これによれば、関数の値は、実引数ごとに独立に値を求め、その値を仮引数に置き換えることでも求めることができる。</p><p>　例えば、expr = f(x, y)とすると、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(expr, Env)<br>= 𝔈(f(x, y), Env)<br>= f(𝔈(x, Env), 𝔈(y, Env))</code></pr></div><p>となる。</p><p>&nbsp;</p><h5>変数の書換え規則</h5><p>　式exprが変数varのみからなる場合、評価関数𝔈の値は参照関数ℜの値に等しい。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(var, Env) = ℜ (Env, var)</code></pr></div><p>&nbsp;</p><h5>変数のない式</h5><p>　式が変数を含まない場合、変数参照が不要なので環境に関係なく式を評価した値が決まる。だが、その式を評価して値を求める手順は、OCamlでの計算そのものになる。これを記述することは、例えば、式"1+1"を評価して値2を導く手順を記述することは、今の実力を考えると不可能である。</p><p>　なので、評価結果を合理的に予想することは諦め、常識に頼り予想する。つまり、式"1+1"について、算数では値が2になるので、OCamlでの評価結果も(理由は一切わからないが)2であると期待する。</p><p>&nbsp;</p><h5>定数の書換え規則</h5><p>　ただし、変数を含まない式が定数である場合には、評価関数𝔈の値は、その定数となる。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(val, Env) = val</code></pr></div><p>&nbsp;</p><p>　以上の準備をもとに問題①を解く。</p><hr><h3>①</h3><h4>式の書換え</h4><p>　OCamlによるlet式の処理を、評価関数𝔈における式の書換えとして模倣していく。書換えは、評価関数𝔈の式がlet式を含まなくなるまで行う。</p><p>　初期の環境をEnv₀とすると、問題の式の評価関数𝔈は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(let x = 1 in let x = 3 in let x = x + 2 in x * x, Env₀)</code></pr></div><p>となる。</p><p>&nbsp;　この式を、let式の書換え規則により書換えると、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;"><pr><code>= 𝔈(let x = 3 in let x = x + 2 in x * x, 𝔇(Env₀, {(x, 𝔈(1, Env₀))}))</code></pr></div><p>となる。</p><p>　ここで、Env₁ = 𝔇(Env₀, {(x, 𝔈(1, Env₀))})とおくと、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 𝔈(let x = 3 in let x = x + 2 in x * x, Env₁)</code></pr></div><p>となる。</p><p>以下同様に、let式の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 𝔈(let x = x + 2 in x * x, 𝔇(Env₁, {(x, 𝔈(3, Env₁))}))</code></pr></div><p>Env₂ = 𝔇(Env₁, {(x, 𝔈(3, Env₁))})とおき、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 𝔈(let x = x + 2 in x * x, Env₂)</code></pr></div><p>let式の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 𝔈(x * x, 𝔇(Env₂, {(x, 𝔈(x + 2, Env₂))}))</code></pr></div><p>Env₃ = 𝔇(Env₂, {(x, 𝔈(x + 2, Env₂))})とおき、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 𝔈(x * x, Env₃)</code></pr></div><p>関数の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 𝔈(x, Env₃) * 𝔈(x, Env₃)</code></pr></div><p>変数の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= ℜ(Env₃, x) * ℜ(Env₃, x)</code></pr></div><p>　以上から、問題式の評価結果を予想するためには、環境Env₃においてxに束縛された値<code>ℜ(Env₃, x)</code>を求めればよいことがわかる。</p><p>&nbsp;</p><h4>環境の導出</h4><p>　環境Env₀から環境Env₃まで順に導いていく。</p><p>&nbsp;</p><h5>Env₀</h5><p>　初期環境Env₀は空とする。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₀ = []</code></pr></div><p>&nbsp;</p><h5>Env₁</h5><p>　上述したようにEnv₁は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₁ = 𝔇(Env₀, {(x, 𝔈(1, Env₀))})</code></pr></div><p>である。右辺における𝔈(1, Env₀)は、評価対象の式が定数1である。そこで、定数の書換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(1, Env₀) = 1</code></pr></div><p>となる。これによりEnv₁は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₁<br>= 𝔇(Env₀, {(x, 1)})<br>= {(x, 1)} ⇢ []<br>= [(x, 1)]</code></pr></div><p>となる。</p><p>&nbsp;</p><h5><code>Env₂</code></h5><p>同様に、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₂ = 𝔇(Env₁, {(x, 𝔈(3, Env₁))})</code></pr></div><p>は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(3, Env₁) = 3</code></pr></div><p>により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₂ = {(x, 3)} ⇢ [(x, 1)] = [(x, 3), (x, 1)]</code></pr></div><p>となる。</p><p>&nbsp;</p><h5><code>Env₃</code></h5><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₃ = 𝔇(Env₂, {(x, 𝔈(x + 2, Env₂))})</code></pr></div><p>について、右辺における𝔈(x + 2, Env₂)は、関数の置換え規則により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(x + 2, Env₂)<br>= 𝔈(x, Env₂) +&nbsp;𝔈(2, Env₂)</code></pr></div><p>となり、前者は変数の置換え規則により、後者は定数の書き換え規則により</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= ℜ(Env₂, x) + 2</code></pr></div><p>となる。</p><p>　ℜ(Env₂, x)は、Env₂ = [(x, 3), (x, 1)]のうち最も左側の要素(x, 3)においてxに束縛された値なので、ℜ(Env₂, x) = 3であり、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 3 + 2<br>= 5</code></pr></div><p>となる。これより、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:10px"><pr><code>Env₃ = {(x, 5)} ⇢ [(x,3), (x, 1)] = [(x, 5), (x, 3), (x, 1)]</code></pr></div><p>となる。</p><p>したがって、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>ℜ(Env₃, x) = 5</code></pr></div><p>である。</p><p>&nbsp;</p><h4>評価結果の予想</h4><p>よって、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>𝔈(let x = 1 in let x = 3 in let x = x + 2 in x * x, Env₀)<br>⋮<br>= ℜ(Env₃, x) * ℜ(Env₃, x)<br>= 5 * 5</code></pr></div><p>となり、5 * 5について、常識により、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>= 25</code></pr></div><p>となる。</p><p>&nbsp;</p><h4>変数の参照と宣言との対応</h4><p>　問題の式において、変数参照がなされている部分式は、x + 2とx * xとの2つである。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>let x = 1 in let x = 3 in let x = <span style="color:#ff0000;">x + 2</span> in <span style="color:#ff0000;">x * x</span></code></pr></div><p>&nbsp;</p><h5>x + 2</h5><p>　x + 2について、その評価関数𝔈(x + 2, Env₂)によれば、xはEnv₂における束縛を参照している。そのEnv₂で変数参照の対象となる束縛は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₂ = 𝔇(Env₁, {(x, 𝔈(3, Env₁))})</code></pr></div><p>より、x = 3の宣言によりなされたものである。</p><p>&nbsp;</p><h5>x * x</h5><p>　x * xについて、評価関数𝔈(x * x, Env₃)によれば、xはEnv₃における束縛を参照し、その参照の対象となる束縛は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>Env₃ = 𝔇(Env₂, {(x, 𝔈(x + 2, Env₂))})</code></pr></div><p>より、x = x + 2の宣言によりなされたものである。</p><p>&nbsp;</p><h4>まとめ</h4><div style="border:double 3px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px">答え: 予想される評価結果は、25である。<br>x + 2におけるxの参照は、宣言x = 3を指す。<br>x * xにおけるxの参照は、宣言x = x + 2を指す。</div><p>&nbsp;</p><p>　OCamlによる式の評価を形式的に表したかったのだが上手くいかなかった。OCamlがどのような原理で計算をしているのか根本的なところが抜けているので解答になっていない。</p><p>　また、環境による変数の宣言・参照についても、機械的に処理できるように表現したつもりだったが、独りよがりでややこしくなっただけだ。がんばるバカほど始末に負えないものはない、という典型のようだ。</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="80%"><p>&nbsp;</p><p><small>上記は、プログラミングinOCaml,五十嵐淳についての感想および練習問題の答案である。著作権を侵害してしまうことがないように問題文は載せていない。ただし、問題文中において、ごく短い文であって、ありふれた表現であり、それのみでは問題としての意味をなさないようなもの(例えば、"- - 1"など)は、著作物にあたらないと判断し、記述している。</small></p>
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12743795840.html</link>
<pubDate>Fri, 20 May 2022 12:00:00 +0900</pubDate>
</item>
<item>
<title>プログラミングinOCaml 練習問題3.3の答案</title>
<description>
<![CDATA[ <h3>練習問題3.3</h3><p>　この問題も練習問題3.2と同様に真理値表を作って解く、と言いたいがHTMLで表を打ち込むのは大変に手間がかかる。</p><p>　そこで、オッカムの論理学大全に載っている方法を使う。構文論的な解法になるが、健全性が成り立つので問題ないだろう。</p><p>&nbsp;</p><h4>連言</h4><p>連言について、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>P ∧ Q<br>&nbsp;⇔ ¬ (¬ P) ∧ ¬ (¬ Q)<br>&nbsp;⇔ ¬ ((¬ P) ∨ (¬ Q))</code></pr></div><p>が成り立つ。</p><p>　したがって、b1 &amp;&amp; b2を書き直すと、</p><div style="border:double 3px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px">答え:　<pr><code>not ((not b1)&nbsp; || (not b2))</code></pr></div><p>となる。</p><p>&nbsp;</p><h4>選言</h4><p>選言について、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>P ∨ Q<br>⇔ ¬ (¬ P) ∨ ¬ (¬ Q)<br>⇔ ¬ ((¬ P) ∧ (¬ Q))</code></pr></div><p>が成り立つ。</p><p>　したがって、b1 || b2を書き直すと、</p><div style="border:double 3px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px">答え:　<pr><code>not ((not b1) &amp;&amp; (not b2))</code></pr></div><p>となる。</p><p>&nbsp;</p><p>　ド・モルガンではなくオッカムを出すところと、論理学大全といいながら論理記号をラテン語で書けない中途半端なところとが、意識高い系らしく書けたと思う。</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="80%"><p>&nbsp;</p><p><small>上記は、プログラミングinOCaml,五十嵐淳についての感想および練習問題の答案である。著作権を侵害してしまうことがないように問題文は載せていない。ただし、問題文中において、ごく短い文であって、ありふれた表現であり、それのみでは問題としての意味をなさないようなもの(例えば、"- - 1"など)は、著作物にあたらないと判断し、記述している。</small></p>
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12743795357.html</link>
<pubDate>Fri, 20 May 2022 12:00:00 +0900</pubDate>
</item>
<item>
<title>プログラミングinOCaml 練習問題3.2の後半の答案と感想</title>
<description>
<![CDATA[ <h3>練習問題3.2</h3><h4>||の書き直し</h4><p>　||の書き直しは、&amp;&amp;の書き直しと同じ手順で行う。</p><p>&nbsp;</p><h5>メタ変数のif式</h5><p>　はじめに、if式の条件部分、then節およびelse節の式を変数A, BおよびCに置き換えて式をたてる。</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if A then B else C</code></pr></div><p>&nbsp;</p><h5>書き直しの条件</h5><p>　次に、A, B, Cを決定する際に考慮すべき点をリストにする。</p><ul style="margin-top:5px;margin-bottom:10px"><li>if式を評価した値は、b1 || b2を評価した値と同じである。</li><li>A, B, Cには{true, false, b1, b2}の要素が入る。</li><li>b1 || b2は、b1が先に評価され、その値がtrueの場合、b2の評価は行われず、式全体の値はtrueとなる。</li><li>b1, b2は、値を持たない場合がある。</li></ul><p>&nbsp;</p><h5>(true|false)が条件の式</h5><p>　次に、Aに入る式がtrueまたはfalseではないことを確認する。Aにtrueを代入したif式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if true then B else C</code></pr></div><p>となり、これの真理値表は、</p><table cellpadding="10" cellspacing="3" width="500"><tbody><tr><th>true</th><th>false</th><th>b1</th><th>b2</th><th>b1 || b2</th><th>if true then B else C</th></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td>U</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td>T*</td><td><span style="background-color:#b6f062;">F*</span></td><td><span style="background-color:#b6f062;">F*</span></td><td><span style="background-color:#b6f062;">F*</span></td><td><span style="background-color:#b6f062;">F*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td>F*</td><td><span style="background-color:#b6f062;">U</span></td><td><span style="background-color:#b6f062;">U</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#b6f062;">U</span></td><td>T*</td><td><span style="background-color:#b6f062;">U</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#b6f062;">U</span></td><td>F*</td><td><span style="background-color:#b6f062;">U</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#b6f062;">U</span></td><td>U</td><td><span style="background-color:#b6f062;">U</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr></tbody></table><p>となる。この表から、true, false, b1およびb2のいずれも、b1 || b2と値が異なる割り当てが存在することが分かる。</p><p>　したがって、Aにtrueが入ることはない。また同様の理由からAにfalseが入ることもない。</p><p>なお、表における記号の意味は以下の通りである。</p><ul style="list-style-type:none;margin-top:5px;margin-bottom:0px;"><li>U: 式が値を持たない状態を示す。</li><li>T*: 式が値を持ち、その値が真である状態を示す。</li><li>F*: 式が値を持ち、その値が偽である状態を示す。</li><li>[B]: Bを評価した値。</li><li>[C]: Cを評価した値。</li></ul><p>&nbsp;</p><h5>b1が条件の式</h5><p>　次に、Aにb1を代入したif式においてBおよびCに入る式を求める。対象となるif式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if b1 then B else C</code></pr></div><p>である。これに対する真理値表は、</p><table cellpadding="10" cellspacing="3" width="500"><tbody><tr><th>true</th><th>false</th><th>b1</th><th>b2</th><th>b1 || b2</th><th>if b1 then B else C</th></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td>U</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td><span style="background-color:#ffb973;">T*</span></td><td>F*</td><td>F*</td><td><span style="background-color:#ffb973;">T*</span></td><td><span style="background-color:#ffb973;">T*</span></td><td><span style="background-color:#ffb973;">[C]</span></td></tr><tr align="center"><td>T*</td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">[C]</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td>F*</td><td><span style="background-color:#ffb973;">U</span></td><td><span style="background-color:#ffb973;">U</span></td><td><span style="background-color:#ffb973;">[C]</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#ff7f7f;">U</span></td><td>T*</td><td><span style="background-color:#ff7f7f;">U</span></td><td><span style="background-color:#ff7f7f;">U</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#ff7f7f;">U</span></td><td>F*</td><td><span style="background-color:#ff7f7f;">U</span></td><td><span style="background-color:#ff7f7f;">U</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#ff7f7f;">U</span></td><td>U</td><td><span style="background-color:#ff7f7f;">U</span></td><td><span style="background-color:#ff7f7f;">U</span></td></tr></tbody></table><p>となる。表から分かるように、Bがtrueまたはb1のとき、[B]がb1 || b2の値と等しくなり、Cがb2のとき、[C]がb1 || b2の値と等しくなる。また、b1 || b2が値を持たないとき、そのときに限り、if式は値を持たない。</p><p>　したがって、b1をAに入れた場合、b1 || b2を書き直したif式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if b1 then (true | b1) else b2</code></pr></div><p>となる。</p><p>&nbsp;</p><h5>b2が条件の式</h5><p>　次に、Aにb2を代入した式</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if b2 then B else C</code></pr></div><p>について、BおよびCに入る式を求める。その真理値表は、</p><table cellpadding="10" cellspacing="3" width="500"><tbody><tr><th>true</th><th>false</th><th>b1</th><th>b2</th><th>b1 || b2</th><th>if b2 then B else C</th></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#b6f062;">U</span></td><td>T*</td><td><span style="background-color:#b6f062;">U</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td><span style="background-color:#ffb973;">T*</span></td><td>F*</td><td><span style="background-color:#ffb973;">T*</span></td><td>F*</td><td><span style="background-color:#ffb973;">T*</span></td><td><span style="background-color:#ffb973;">[C]</span></td></tr><tr align="center"><td>T*</td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">[C]</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#ffb973;">U</span></td><td>F*</td><td><span style="background-color:#ffb973;">U</span></td><td><span style="background-color:#ffb973;">[C]</span></td></tr><tr align="center"><td><span style="background-color:#ff7f7f;">T*</span></td><td>F*</td><td><span style="background-color:#ff7f7f;">T*</span></td><td>U</td><td><span style="background-color:#ff7f7f;">T*</span></td><td>U</td></tr><tr align="center"><td>T*</td><td>F*</td><td>F*</td><td><span style="background-color:#ff7f7f;">U</span></td><td><span style="background-color:#ff7f7f;">U</span></td><td><span style="background-color:#ff7f7f;">U</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td>U</td><td><span style="background-color:#ff7f7f;">U</span></td><td><span style="background-color:#ff7f7f;">U</span></td><td><span style="background-color:#ff7f7f;">U</span></td></tr></tbody></table><p>となる。表から分かるように、Bには{true, false, b1, b2}のいずれの要素も入らない。</p><p>　より詳細には、真理値表の1-3行におけるb1 || b2の値に対し、trueおよびb2は3行での値が一致せず、falseは1-3行での値が一致せず、b1は2行での値が一致していない。</p><p>　さらに、BおよびCにいずれの式を代入するかに拘らず、if式の値がb1 || b2の値と一致しない割り当てが存在する。すなわち、7行では、b2の値がUであるためにif式の値もUになってしまう。そのため、if式の値がb1 || b2の値T*に一致することはありえない。</p><p>　したがって、Aにb2が入ることはない。</p><p>&nbsp;</p><h5>まとめ</h5><p>以上から、Aにはb1のみが入ることになる。よって、</p><div style="border:double 3px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px">答え:<br><pr><code>&nbsp;if b1 then true else b2</code></pr><br>または、<br><pr><code>&nbsp;if b1 then b1 else b2</code></pr></div><p>である。</p><p>&nbsp;</p><h4>ifの使用回数</h4><p>　上述の答えは、ifの使用回数を1度に制限したものであった。制限しない場合の答えとしては、以下のものが考えられる。</p><p>　答えの式についての生成規則を、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code><span style="font-style:italic;">expr</span> ::= if b1 then true else b2<br>&nbsp;| if b1 then b1 else b2<br>&nbsp;| if <span style="font-style:italic;">expr</span> then (true|<span style="font-style:italic;">expr</span>) else (false|<span style="font-style:italic;">expr</span>)<br>&nbsp;| if true then <span style="font-style:italic;">expr</span> else (true|false|expr)<br>&nbsp;| if false then (true|false|<span style="font-style:italic;">expr</span>) else <span style="font-style:italic;">expr</span></code></pr></div><p>とすれば、生成されるif式は、また答えとなる。</p><p>&nbsp;</p><h3>蛇足</h3><p>　真理値表の扱いにも慣れたので、他の論理演算子について定義してみる。対象は、排他的選言と、シェファストロークとする。</p><p>　真理値表は、</p><table cellspacing="10" width="500"><tbody><tr><th>true</th><th>false</th><th>b1</th><th>b2</th><th>b1 ⊻ b2</th><th>b1 | b2</th></tr><tr align="center"><td>T</td><td>F</td><td>T</td><td>T</td><td>F</td><td>F</td></tr><tr align="center"><td>T</td><td>F</td><td>T</td><td>F</td><td>T</td><td>T</td></tr><tr align="center"><td>T</td><td>F</td><td>F</td><td>T</td><td>T</td><td>T</td></tr><tr align="center"><td>T</td><td>F</td><td>F</td><td>F</td><td>F</td><td>T</td></tr></tbody></table><p>となる。</p><p>　この表で、問題となるのは1,2行であろう。1, 2行におけるb1 ⊻ b2およびb1 | b2の値は、true, false, b1, b2のいずれの値とも一致していない。</p><p>　ここで、b1 ⊻ b2およびb1 | b2の値が、b2の値の否定となっていることに注目する。そのb2の否定は、もう1つif式を使えば容易に定義できる。</p><p>　したがって、if式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:50px"><pr><code> b1 ⊻ b2 ⇔ if b1 then (if b2 then false else true) else b2<br>b1 | b2 ⇔ if b1 then (if b2 then false else true) else true<br>not b2 ⇔ if b2 then false else true</code></pr></div><p>となる。</p><p>　排他的選言もシェファストロークも1つのif式では表すことができない。1つのif式と{true, false, b1, b2}のみによる書き直しは表現的適格性を欠いているのだろう。</p><p>&nbsp;</p><h3>練習問題3.2の感想</h3><p>　本問は、問題が前提としている式の範囲でずいぶんと悩んだ。より詳しくは、範囲のなかに例外が発生する式を含めるべきか否かについてだ。含めることにすると、論理演算子や書き直したif式が可換でなくなり、どうにも気持ちがわるい。</p><p>　例外という言葉の響きからは、例外が発生するような式は、OCamlにおける正当な式ではない、という印象を受ける。</p><p>　そこで、当初の答案では、式の範囲を限定して、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:50px">なお、論理演算子の引数は、評価の際にエラーが発生しない式とする。</div><p>や、"同じ意味"の判断をメタではなくOCamlで行うことにして、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:50px">ただし、同じ意味の書き直しとは、<br><pr><code>(b1 &amp;&amp; b2) = (if ... then ... else ...)</code></pr><br>を評価した値が任意のb1, b2についてtrueになることをいう。</div><p>などの、なお書き、ただし書きを付けることにしていた。</p><p>　だが、常識的に考えて、なお書きやただし書きを付けたものは、もはや答案でもなんでもない。問題が上手く解けないからといって、問題を変更しているようなものだ。</p><p>　なので、結局は例外発生の式も含めて式の範囲を広く取るようにした。</p><p>　感想というよりも言い訳になってしまった。やはり、いまでも、どこか納得がいってない部分があるのだろう。</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="80%"><p>&nbsp;</p><p><small>上記は、プログラミングinOCaml,五十嵐淳についての感想および練習問題の答案である。著作権を侵害してしまうことがないように問題文は載せていない。ただし、問題文中において、ごく短い文であって、ありふれた表現であり、それのみでは問題としての意味をなさないようなもの(例えば、"- - 1"など)は、著作物にあたらないと判断し、記述している。</small></p>
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12743655448.html</link>
<pubDate>Thu, 19 May 2022 20:20:16 +0900</pubDate>
</item>
<item>
<title>プログラミングinOCaml 練習問題3.2の前半の答案</title>
<description>
<![CDATA[ <h3>練習問題3.2</h3><h4>式の意味？</h4><p>　またもや題意がつかめない。本問は、論理演算子の式を"同じ意味"になるように書き直せ、というものだ。だが、式の意味とは何だろう。これまでのところ、式の"評価"や"値"については説明があったが、"意味"についてはなかったように思う。</p><p>　もしかすると、"意味"は、式に掛かるのではないのかもしれない。例えば、掛け算の式を足し算の式に書き換える場合、"同じ意味"になるようにとは言わないだろう。とすれば、"同じ意味"は論理演算子に掛かっていることになる。</p><p>&nbsp;</p><h4>論理演算子の意味</h4><p>　そこで、論理演算子について本文を読み直してみたところ、&amp;&amp;は"かつの意味"であるとの記述があった。なんのことはない、"意味"はコンピュータ用語ではなく日常語だったのだ。</p><p>　ならば、論理演算子の式の意味とは、引数にbool型の式を割り当てて評価したときの値のことになる。例えば、A &amp;&amp; Bという式の場合、割り当てをA=true, B=falseとすると、式の意味はfalseになるということだろう。</p><p>&nbsp;</p><h4>題意</h4><p>&nbsp;　以上から、本問の題意は、真理値を返すif式であって、任意の割り当て対して論理演算子の式の値と同じ値を返すif式を作れ、というものになる。</p><p>&nbsp;</p><h4>&amp;&amp;の書き直し</h4><p>　if式の条件, then節およびelse節を変数A, B, Cにして式をたてると、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if A then B else C</code></pr></div><p>となる。さて、このif式のA, B, Cに何を入れればよいだろうか。その際、考慮すべき点は、</p><ul><li>if式を評価して得られる値は、b1 &amp;&amp; b2を評価して得られる値と同じでなければならない。</li><li>A, B, Cには、{b1, b2, true, false}のうちのいずれかが入る。</li></ul><p>である。</p><p>&nbsp;</p><h5>場合分けしないif式</h5><p>　直感的に考えて条件のAにtrueやfalseが入ることはない。まずは、これを確かめる。Aにtrueを代入するとif式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if true then B else C ⇔ B</code></pr></div><p>となる。このif式の値は、割り当てによらず、Bの値(これを[B]と表す)と同じになる。真理値表で表すと、</p><table cellpadding="10"><tbody><tr><th>true&nbsp;&nbsp;</th><th>false&nbsp;&nbsp;</th><th>b1&nbsp;&nbsp;</th><th>b2&nbsp;&nbsp;</th><th>b1&amp;&amp;b2&nbsp;&nbsp;</th><th>if true then B else C</th></tr><tr align="center"><td>T</td><td><span style="color:#bfbfbf;">F</span></td><td>T</td><td>T</td><td>T</td><td>[B]</td></tr><tr align="center"><td><span style="color:#bfbfbf;">T</span></td><td>F</td><td><span style="color:#bfbfbf;">T</span></td><td>F</td><td>F</td><td>[B]</td></tr><tr align="center"><td><span style="color:#bfbfbf;">T</span></td><td>F</td><td>F</td><td><span style="color:#bfbfbf;">T</span></td><td>F</td><td>[B]</td></tr><tr align="center"><td><span style="color:#bfbfbf;">T</span></td><td>F</td><td>F</td><td>F</td><td>F</td><td>[B]</td></tr></tbody></table><p>となる。</p><p>　この場合、Bに{b1, b2, true, false}のうちのいずれかを入れたとしても、[B]がb1 &amp;&amp; b2の値と等しくならない割り当てが存在する。</p><p>　真理値表でいえば、b1, b2, true, falseのどの列においても、少なくとも一つの行でb1 &amp;&amp; b2と真理値が一致しない。</p><p>　したがって、Aにtrueが入ることはない。</p><p>&nbsp;</p><p>　同様に、falseがAに入ることもない。つまり、Aにfalseを代入したif式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if false then B else C ⇔ C</code></pr></div><p>となり、その値が常に[C]となってしまう。</p><p>&nbsp;</p><h5>b1が条件のif式</h5><p>　以上からAにはb1かb2が入ることになる。 ここでは、Aにb1を代入した場合を考える。その場合if式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if b1 then B else C</code></pr></div><p>となる。このif式の値は、b1が真のときに[B]、b1が偽のときに[C]である。真理値表は、</p><table cellpadding="10"><tbody><tr><th>true&nbsp;&nbsp;</th><th>false&nbsp;&nbsp;</th><th>b1&nbsp;&nbsp;</th><th>b2&nbsp;&nbsp;</th><th>b1&amp;&amp;b2&nbsp;&nbsp;</th><th>if b1 then B else C</th></tr><tr align="center"><td><span style="background-color:#d9ffa2;">T</span></td><td>F</td><td><span style="background-color:#d9ffa2;">T</span></td><td><span style="background-color:#d9ffa2;">T</span></td><td><span style="background-color:#d9ffa2;">T</span></td><td><span style="background-color:#d9ffa2;">[B]</span></td></tr><tr align="center"><td>T</td><td><span style="background-color:#ffbfbf;">F</span></td><td>T</td><td><span style="background-color:#ffbfbf;">F</span></td><td><span style="background-color:#ffbfbf;">F</span></td><td><span style="background-color:#ffbfbf;">[B]</span></td></tr><tr align="center"><td>T</td><td>F</td><td>F</td><td>T</td><td>F</td><td>[C]</td></tr><tr align="center"><td>T</td><td>F</td><td>F</td><td>F</td><td>F</td><td>[C]</td></tr></tbody></table><p>となる。</p><p>&nbsp;</p><h5>Bの式</h5><p>　次に、Bに入る式を考える。Bに注目して真理値表を見ると、1, 2行でif式の値が[B]となっている。つまり、Bに入る式の値が、1, 2行におけるif式の値となる。そのif式の値は、b1 &amp;&amp; b2の真理値と一致しなければならない。</p><p>　したがって、Bに代入する式は、1, 2行での値がb1 &amp;&amp; b2の真理値と同じであるものを選べばよいことになる。</p><p>　各行ごとに条件に合う式を選んでいく。</p><p>　1行目のb1 &amp;&amp; b2の真理値はTである。{b1, b2,true,false}のなかで1行目がTになるのはtrueとb1とb2である。</p><p>　2行目のb1 &amp;&amp; b2の真理値はFである。{b1, b2,true,false}のなかで2行目がFになるのはfalseとb2である。</p><p>　1, 2行の両方が一致するのはb2のみである。したがって、Bにはb2が入ることになる。</p><p>これによりif式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if b1 then b2 else C</code></pr></div><p>となる。その真理値表は、</p><table cellpadding="10"><tbody><tr><th>true&nbsp;&nbsp;</th><th>false&nbsp;&nbsp;</th><th>b1&nbsp;&nbsp;</th><th>b2&nbsp;&nbsp;</th><th>b1&amp;&amp;b2&nbsp;&nbsp;</th><th>if b1 then b2 else C</th></tr><tr align="center"><td>T</td><td>F</td><td>T</td><td>T</td><td>T</td><td>T</td></tr><tr align="center"><td>T</td><td>F</td><td>T</td><td>F</td><td>F</td><td>F</td></tr><tr align="center"><td>T</td><td><span style="background-color:#ffbfbf;">F</span></td><td><span style="background-color:#ffbfbf;">F</span></td><td>T</td><td><span style="background-color:#ffbfbf;">F</span></td><td><span style="background-color:#ffbfbf;">[C]</span></td></tr><tr align="center"><td>T</td><td><span style="background-color:#ffbfbf;">F</span></td><td><span style="background-color:#ffbfbf;">F</span></td><td><span style="background-color:#ffbfbf;">F</span></td><td><span style="background-color:#ffbfbf;">F</span></td><td><span style="background-color:#ffbfbf;">[C]</span></td></tr></tbody></table><p>となる。</p><p>&nbsp;</p><h5>Cの式</h5><p>　残ったCについても、Bのときと同様にして入る式を考える。真理値表でCに注目すると、if式の値が[C]となるのは3,4行であり、その3,4行でのb1 &amp;&amp; b2の真理値はいずれもFになっている。</p><p>　したがって、Cには3, 4行でFとなる式、b1かfalseが入る。これによりif式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if b1 then b2 else false</code></pr></div><p>または</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if b1 then b2 else b1</code></pr></div><p>となり、真理値表は、</p><table cellpadding="10"><tbody><tr><th>true&nbsp;&nbsp;</th><th>false&nbsp;&nbsp;</th><th>b1&nbsp;&nbsp;</th><th>b2&nbsp;&nbsp;</th><th>b1&amp;&amp;b2&nbsp;&nbsp;</th><th>if b1 then b2 else (false|b1)</th></tr><tr align="center"><td>T</td><td>F</td><td>T</td><td>T</td><td>T</td><td>T</td></tr><tr align="center"><td>T</td><td>F</td><td>T</td><td>F</td><td>F</td><td>F</td></tr><tr align="center"><td>T</td><td>F</td><td>F</td><td>T</td><td>F</td><td>F</td></tr><tr align="center"><td>T</td><td>F</td><td>F</td><td>F</td><td>F</td><td>F</td></tr></tbody></table><p>となる。</p><p>　この真理値表では、確かにb1 &amp;&amp; b2の列とif式の列とにおける真理値が、すべての行において一致している。</p><p>&nbsp;</p><h4>&amp;&amp;の特別ルール</h4><p>　ところで、条件Aの式に戻ると、Aにb1を代入したのは任意であった。なので普通に考えれば、b1とb2とを入れ替えたif式も"同じ意味"の式になるだろう。</p><p>　しかし、OCamlの論理演算子&amp;&amp;には気になるルールがある。それは、b1 &amp;&amp; b2の値は、b1の値がfalseの場合、b2の値に拘らずfalseになるというものだ。</p><p>　これによれば、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>b1 &amp;&amp; b2　⇔ if b2 then b1 else false</code></pr></div><p>が成り立たない場合があるのではないだろうか。例えば、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>b1: false<br>b2: int_of_string "0xg" = 16</code></pr></div><p>とする。この場合、論理演算子&amp;&amp;の式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>#&nbsp;false &amp;&amp; int_of_string "0xg" = 16;;<br>- : bool = false </code></pr></div><p>となり、その値はfalseである。これに対して、if式は、</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>#&nbsp;if int_of_string "0xg" = 16 then false else false;;<br>Exception: Failure "int_of_string". </code></pr></div><p>となり、値がない。</p><p>　このように、b1とb2とを入れ替えたif式(b2が条件のif式)は、b2の評価において例外が発生する場合、&amp;&amp;の式と同じ意味にならない。</p><p>&nbsp;</p><h4>宇宙</h4><p>　さて、上述のような例外が起きる式は、本問を解くにあたり、&amp;&amp;の引数として考慮に入れるべきものなのだろうか。</p><p>　ここでは、例外が実行時のエラーであることを理由に、例外が起きる式も引数にしたいと思う。</p><p>　より詳細には、本文2.1.3に説明があるように、OCaml(コンパイラ)にとって、実行前の型検査(当然、構文検査も)をパスできた式は、"よい式"なのだ。つまりコンパイラが保証を与えるのは型付けエラーが発生しないことまでで、実行時の例外が発生しないことについては保証がない。</p><p>　このような<span style="font-weight:bold;">発生しない</span>ことが保証されてないエラーは、<span style="font-weight:bold;">発生する</span>ものとして扱うのが妥当だろう。OCamlの世界ではコンパイラ様が絶対で、そのコンパイラ様がOKを出したのだから、それに従うべきなのだ。</p><p>　以上から、&amp;&amp;の引数の式には、例外が発生する式も含むとして、その書き直しを行うことにする。</p><p>&nbsp;</p><h4>やり直し</h4><p>　書き直しは、これまでの真理値表をつかった手順をベースにし、さらに、A, B, Cに入る式を決めるにあたって、</p><ul><li>論理演算子&amp;&amp;の第1引数についての特別ルール。</li><li>引数の式b1, b2は、値を持たない場合がある。</li></ul><p>も考慮する。</p><p>&nbsp;</p><h5>状態表</h5><p>　この方針をもとに真理値表を作り直す。新しい真理値表では、式の値が存在しない状態をUで表すことにする。さらに、式の値が存在し、その値がTである状態をT*で表し、式の値が存在し、その値がFである状態をF*で表す。</p><p>　わざわざ記号をT*, F*に変更するは、これまでのT, FがOCamlでの値を表していたのに対し、T*, F*はメタから見た式の状態を表すからである。</p><p>&nbsp;</p><h5>b1が条件のif式</h5><p>　まず、b1を条件としたif式</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if b1 then b2 else (false|b1)</code></pr></div><p>について確認する。このif式の真理値表は、</p><table cellpadding="10"><tbody><tr><th>true&nbsp;&nbsp;</th><th>false&nbsp;&nbsp;</th><th>b1&nbsp;&nbsp;</th><th>b2&nbsp;&nbsp;</th><th>b1&amp;&amp;b2&nbsp;&nbsp;</th><th>if b1 then b2 else (false|b1)</th></tr><tr align="center"><td><span style="background-color:#b6f062;">T*</span></td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">T*</span></td></tr><tr align="center"><td>T*</td><td><span style="background-color:#b6f062;">F*</span></td><td>T*</td><td><span style="background-color:#b6f062;">F*</span></td><td><span style="background-color:#b6f062;">F*</span></td><td><span style="background-color:#b6f062;">F*</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td>T*</td><td><span style="background-color:#b6f062;">U&nbsp;</span></td><td><span style="background-color:#b6f062;">U&nbsp;</span></td><td><span style="background-color:#b6f062;">U</span>&nbsp;</td></tr><tr align="center"><td>T*</td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td>T*</td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td></tr><tr align="center"><td>T*</td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td></tr><tr align="center"><td>T*</td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td><td>U&nbsp;</td><td><span style="background-color:#ffb973;">F*</span></td><td><span style="background-color:#ffb973;">F*</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#ff7f7f;">U&nbsp;</span></td><td>T*</td><td><span style="background-color:#ff7f7f;">U</span>&nbsp;</td><td><span style="background-color:#ff7f7f;">U&nbsp;</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#ff7f7f;">U&nbsp;</span></td><td>F*</td><td><span style="background-color:#ff7f7f;">U</span>&nbsp;</td><td><span style="background-color:#ff7f7f;">U&nbsp;</span></td></tr><tr align="center"><td>T*</td><td>F*</td><td><span style="background-color:#ff7f7f;">U&nbsp;</span></td><td>U&nbsp;</td><td><span style="background-color:#ff7f7f;">U&nbsp;</span></td><td><span style="background-color:#ff7f7f;">U&nbsp;</span></td></tr></tbody></table><p>である。このif式は、b1, b2の評価の順序がb1 &amp;&amp; b2と同じなので、すべての割り当てにおいてb1 &amp;&amp; b2と同じ値(状態)をとることになる。</p><p>　よって、このif式は、例外の発生を考慮したとしても、b1 &amp;&amp; b2を同じ意味で書き直したものといえる。</p><p>&nbsp;</p><h5>b2が条件のif式</h5><p>　次に、b2を条件としたif式</p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code>if b2 then B else C</code></pr></div><p>について書き直しを試みる。真理値表は、</p><table cellpadding="10"><tbody><tr><th>&nbsp;&nbsp;</th><th>true&nbsp;&nbsp;</th><th>false&nbsp;&nbsp;</th><th>b1&nbsp;&nbsp;</th><th>b2&nbsp;&nbsp;</th><th>b1&amp;&amp;b2&nbsp;&nbsp;</th><th>if b2 then B else C</th></tr><tr align="center"><td>1</td><td>T*</td><td>F*</td><td><span style="background-color:#b6f062;">T*</span></td><td>T*</td><td><span style="background-color:#b6f062;">T*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td>2</td><td>T*</td><td><span style="background-color:#ff7f7f;">F*</span></td><td>T*</td><td><span style="background-color:#ff7f7f;">F*</span></td><td><span style="background-color:#ff7f7f;">F*</span></td><td><span style="background-color:#ff7f7f;">[C]</span></td></tr><tr align="center"><td>3</td><td>T*</td><td>F*</td><td>T*</td><td><span style="background-color:#ffb973;">U</span>&nbsp;</td><td><span style="background-color:#ffb973;">U</span>&nbsp;</td><td><span style="background-color:#ffb973;">U</span>&nbsp;</td></tr><tr align="center"><td>4</td><td>T*</td><td>F*</td><td><span style="background-color:#b6f062;">F*</span></td><td>T*</td><td><span style="background-color:#b6f062;">F*</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td>5</td><td>T*</td><td><span style="background-color:#ff7f7f;">F*</span></td><td>F*</td><td><span style="background-color:#ff7f7f;">F*</span></td><td><span style="background-color:#ff7f7f;">F*</span></td><td><span style="background-color:#ff7f7f;">[C]</span></td></tr><tr align="center"><td>6</td><td>T*</td><td>F*</td><td>F*</td><td>U&nbsp;</td><td>F*</td><td>U&nbsp;</td></tr><tr align="center"><td>7</td><td>T*</td><td>F*</td><td><span style="background-color:#b6f062;">U&nbsp;</span></td><td>T*</td><td><span style="background-color:#b6f062;">U&nbsp;</span></td><td><span style="background-color:#b6f062;">[B]</span></td></tr><tr align="center"><td>8</td><td>T*</td><td>F*</td><td>U&nbsp;</td><td>F*</td><td>U&nbsp;</td><td>[C]</td></tr><tr align="center"><td>9</td><td>T*</td><td>F*</td><td>U&nbsp;</td><td><span style="background-color:#ffb973;">U</span>&nbsp;</td><td><span style="background-color:#ffb973;">U</span>&nbsp;</td><td><span style="background-color:#ffb973;">U</span>&nbsp;</td></tr></tbody></table><p>である。</p><p>　Bについては、1, 4, 7行のb1 &amp;&amp; b2の値とb1の値とが同じなので、b1を入れることができる。</p><p>　Cについては、2, 5行ではb1 &amp;&amp; b2の値とfalseおよびb2の値とが一致するものの、8行ではb1 &amp;&amp; b2の値Uは、falseおよびb2のいずれの値とも一致していない。したがって、Cに入る式は存在しない。</p><p>　さらに、6行については、B, Cになにを代入したとしても、if式の値Uが、b1 &amp;&amp; b2の値F*と一致することはない。これは、b2の値がUならばif式は必ずUになるからであり、条件Aにb2を代入する限りどうしようもない。</p><p>　よって、このif式は、b1 &amp;&amp; b2を書き直したものではない。</p><p>&nbsp;</p><h5>まとめ</h5><p>　以上、b1 &amp;&amp; b2を同じ意味のif式に書き直すには、条件をb1にしなければならないことが確かめられた。</p><div style="border:double 3px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px">答え:<br><pr><code> 　if b1 then b2 else false </code></pr><br>または、<br><pr><code> 　if b1 then b2 else b1 </code></pr></div><p>&nbsp;</p><h4>ifの使用回数</h4><p>　なお、ifの使用回数を1度に限定しない場合の答えとして、例えば、以下のものがある。</p><p>　式<code>fₘを、</code></p><div style="border:solid 1px #c0c0c0;padding:5px;margin:10px;margin-left:30px;margin-right:100px"><pr><code> f₁:</code></pr> 上述の答えの式のいずれか。<br><pr><code>fₙ₊₁: if true then fₙ else false</code></pr><br>(fₙは答えのif式であってifの使用回数がn度のもの。)</div><p>と定義する。</p><p>　このとき、<pr><code>fₘ(m ∈ ω∖{0})</code></pr>は、答えである。</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><hr align="center" width="80%"><p><small>上記は、プログラミングinOCaml,五十嵐淳についての感想および練習問題の答案である。著作権を侵害してしまうことがないように問題文は載せていない。ただし、問題文中において、ごく短い文であって、ありふれた表現であり、それのみでは問題としての意味をなさないようなもの(例えば、"- - 1"など)は、著作物にあたらないと判断し、記述している。</small></p>
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12743655187.html</link>
<pubDate>Thu, 19 May 2022 20:18:48 +0900</pubDate>
</item>
<item>
<title>プログラミングinOCaml 練習問題3.1の感想</title>
<description>
<![CDATA[ <h4>正解を確かめたい</h4><p>　練習問題3.1を解いた後で、正解もOCamlで確かめようとしたところ困ったことになった。つまり、</p><ul><li>何をもって正解とするのか？</li><li>その判断をOCamlだけで行えるのか？</li></ul><p>が分からないのである。この疑問を解決するには、どう考えればよいのだろう。</p><p>&nbsp;</p><p>　1つには、外延を用いることが考えられる。この場合は、"正しい"外延と同じ外延を持つものが正解となる。それでは、OCamlの関数の外延はどのように求めればよいのだろうか。</p><p>&nbsp;</p><p>　これを求めることは、現実的には相当に困難だと思われる。なぜなら、関数から外延を求める手続きがあったとすると、この手続きはまた関数となり、これが循環を引き起こすように思えるからだ。</p><p>&nbsp;</p><p>　例えば、外延を求める汎用的な関数があったとする。その場合、汎用関数の外延には、すべての関数(についての順序対)が含まれるので、汎用関数自体も含まれることになり循環してしまう。</p><p>&nbsp;</p><p>　また、汎用的な関数ではなく、関数ごとに外延関数があったとする。その外延関数が求めた外延は、はたして正しいだろうか。それを確かめるには、その外延関数の外延を求める別の外延関数が必要になる。そして、その別の外延関数が正しいかどうかは、さらに別の外延関数が必要になり、循環してしまう。</p><p>&nbsp;</p><h4>諦める</h4><p>　興味はつきないものの、これは俺の能力を完全に越えた話題だろう。考察らしきことをしたいならば、プログラムの意図する動作(つまり"正解")や同一性などの概念を、単純化、抽象化して問題を絞り込む必要がありそうだ。そうでなければ、延々と"～とは何か"が続く似非哲学に陥ってしまう。もっとも、意識高い系としては、そちらが本線ではあるが。</p><p>　畢竟(使ってみたかった)、プログラミングには、これぞ正答と呼べるものはないのではなかろうか。</p>
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12743654552.html</link>
<pubDate>Thu, 19 May 2022 20:15:11 +0900</pubDate>
</item>
<item>
<title>プログラミングinOCaml　3.3の感想と練習問題3.1の答案</title>
<description>
<![CDATA[ <h3>本文の感想</h3><p>この節は、内容に比して説明が多いせいかスムーズに理解できた。他の説明もこのぐらいだとありがたいのだが、それだと厚さが倍以上になってしまうだろう。想定される読者(大学生)より劣るのだから難しく感じるのはしかたがない、とは僻みがすぎるだろうか。</p><h4>環境</h4><p>環境のしくみは、紙に書いて計算する場合に似ているので理解しやすい。環境を長いスクロールのように、上から下に向かって書き込むものと考えるとしっくりくる。本文中でも、スタックは上に積まれず下に延びる。</p><h4>有効範囲</h4><p>有効範囲は、静的有効範囲のほうがOCamlにとって自然なのではないか。OCamlの変数は名前が付けられた値に過ぎない。なので関数定義に含まれる変数(仮引数ではない)をそのまま値に置き換えても、定義の内容が変わらないことが期待される。この期待に静的有効範囲はマッチしていると思う。</p><p>それに対して、動的有効範囲は、OCamlの変数の扱い方と相容れない気がする。動的有効範囲は、例えば、具体的な値が束縛されてない変数、いわゆる自由変数を使って関数を定義できるような言語にこそあうのではないか。</p><h3>練習問題3.1</h3><h3>①</h3><p>手を使った場合にどのような解き方になるのか考える。ナイーブに考えると、その解き方は、「ドルにレートを掛けて、その積を四捨五入して円を求める」になるだろう。</p><p>ここで、四捨五入には、積と0.5との和を小数点以下で切り捨てるという手順が考えられる。また、レートは、問題文で指定された114.32に固定されているとする。</p><p>これでドルが円に換算される。ただし、OCamlには型があることを考慮しなければならない。つまり、換算した円は、そのままではfloat型データになるので、int型データへの変換が必要となる。以上を整理すると、</p><ul><li>レートを表す変数rateを114.32として定義する。</li><li>四捨五入の関数roundを定義する。その本体は、引数と0.5との和を小数点以下で切り捨てるものなる。なお、切り捨てには関数floorを使う。</li><li>ドルとrateの積にroundを適用して円に換算し、その結果をint_of_floatで変換する。</li></ul><p>になる。これをOCamlで表すと、</p><div class="answer"><div class="ocaml-src">let dollar_to_yen x =   let rate = 114.32 in   let round y = floor (y +. 0.5) in   int_of_float (round (x *. rate))</div></div><p>この答えは、レートごとに関数を定義しなければならないのでいまひとつである。こういうときに、動的有効範囲が役に立つのだろう。動的有効範囲ならば、rateを大域環境で定義するだけで、レート変動に応じて円換算できる。</p><h3>②</h3><p>考え方は、①と同じである。</p><div class="answer"><div class="ocaml-src">let yen_to_dollar x =   let dollars_to_cents_rate = 100.0 in   let dollars_to_cents y = y *. dollars_to_cents_rate in   let cents_to_dollars y = y /. dollars_to_cents_rate in   let round y = cents_to_dollars (floor ((dollars_to_cents y) +. 0.5)) in   let usd_to_jpy_rate = 114.32 in   round ((float_of_int x) /. usd_to_jpy_rate)</div></div><p>1ドルが何セントなのか分からなかった。大学生には常識なのだろうか。とりあえず、何セントでもいいように解いた。</p><p>調べると、"セント"はそのまま100の意味だった。Decemberが12月になるような言語なのに意外にまともだった。</p><h3>③</h3><p>①のdollar_to_yenが大域環境に定義されていることを前提として解くことにする。</p><p>その場合、ドルと、そのドルをdollar_to_yenで換算した円とを文字列に変換し、それら文字列と、問題文で指定された横文字とを連結すればよい。</p><div class="answer"><div class="ocaml-src">let dollar_to_yen x = (string_of_float x)   ^ " dollars are "   ^ (string_of_int (dollar_to_yen x))   ^ " yen."</div></div><p>大域環境にある①のdollar_to_yenを使って③のdollar_to_yenを再定義した。再定義は、環境についての理解を確かめる意味もあって、あえて行った。決して、関数名を考えるのが面倒くさかったからではない。</p><h3>④</h3><p>char型データのクラスは、lexical orderで順序づけられており、[0, 255]への同型写像int_of_charが存在する。これより、'a'からn番目の小文字cについて、</p><div class="formulae">int_of_char c = int_of_char 'a' + n</div><p>となる。同様に'A'からn番目の大文字Cについて、</p><div class="formulae">int_of_char C = int_of_char 'A' + n</div><p>となる。これらの式より</p><div class="formulae">int_of_char C = int_of_char 'A' + int_of_char c - int_of_char 'a'</div><p>が成り立つ。ここで、int_of_charは同型写像なので逆写像が存在する。その逆写像はchar_of_intである。そのchar_of_intにより、上式の等号の両辺をchar型に変換すると、</p><div class="formulae">C = char_of_int (int_of_char 'A' + int_of_char c - int_of_char 'a')</div><p>となる。したがって、小文字cを大文字Cに変換する関数uppercaseは、</p><div class="formulae">let uppercase c = char_of_int (int_of_char 'A' + int_of_char c - int_of_char 'a')</div><p>となる。このuppercaseを用いてcapitalizeを定義する。具体的には、文字cが小文字以外のときと、小文字のときとで場合分けし、小文字以外のときはそのままcを、小文字のときはuppercase cの値を返す。</p><div class="answer"><div class="ocaml-src">let capitalize c =   let uppercase d =      char_of_int (int_of_char 'A' + int_of_char d - int_of_char 'a') in   if c &lt; 'a' || 'z' &lt; c then c else uppercase c</div></div><hr class="copyright">
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12569950354.html</link>
<pubDate>Mon, 03 Feb 2020 00:00:00 +0900</pubDate>
</item>
<item>
<title>プログラミングinOCaml　3.2の感想</title>
<description>
<![CDATA[ <h3>本文の感想</h3><h4>if式への違和感</h4><p>やはり、3.1で疑問がなかったのは理解が浅かったからだ。さっそくif式でつまづいた。条件が偽のときにも式が必要なところが分からない。</p><p>&nbsp;</p><p>場合分けとして考えれば、真と偽との両方に式が必要になるのは当然なのだが。</p><p>&nbsp;</p><p>しかし、函数を定義するだけならば、then節だけでも十分に思われる。else節がなければ定義域が制限される、というのではだめなのだろうか。例えば、if式を、条件が0以上の整数、かつthen節のみを持つとした場合には、その定義域が自然数に制限された函数が定義される、とはできないのだろうか。</p><p>&nbsp;</p><p>これができないのは、おそらく、型の部分（上記の例では自然数）からなる型(部分型とでもいうべきものか)を定義できないからだろう。</p><p>&nbsp;</p><p>この部分型が定義できないというのは、OCamlが静的型付き言語であることが理由だろう。静的型付き言語はその名前の通り静的に（つまりプログラムの実行前に）型検査を行う。</p><p>一方、部分型を定義するには、型の部分を特定する必要があり、その特定には一般に式の評価が必要となる。上述の例でいえば、自然数を特定するには、0以上の整数ならば真、という式の評価が必要となる。</p><p>ところが、この式の評価というのはプログラムの実行である。つまり、静的型付け言語では、プログラムの実行前に行うべき部分型の型検査において、プログラムの実行が必要になってしまう。したがって、静的型付け言語では、部分型の定義（正確にはプログラムの実行を必要とする定義）ができない。</p><p>型を部分に分けられないなら、全体で函数を定義せざるをえない。よって、OCamlのif式では、else節を省略することができないことになる。</p><p>&nbsp;</p><p>つまづいた原因は、if式への理解不足というよりも、型についての勘違いだった。静的型というのは、その実現に困難さがあるものの、安全性の高い記述を可能とするものであり、関数の引数などにまつわる問題をほぼ排除できると、なんとなく思い込んでいた。だが、それほどではないのかもしれない。</p><h4>関数とは何か？</h4><p>結局のところ、OCamlの関数は数学の函数とは違うものであり、同じものだとの思い込みが理解を妨げているようだ。型は集合ではないし、関数fの型int-&gt;intは、dom(f)=int、rang(f)⊆intを表しているのではない。ZFの函数などとは切り離してOCamlの関数を理解する必要がある。</p><p>&nbsp;</p><p>ならばOCamlにおける関数をどのようにとらえればよいだろうか。現段階の理解では、</p><div class="formulae">引数から値を求めるための手続きであって、引数と値の型を属性として持つもの</div>となるだろうか。曖昧だがしかたがない。まだまだ3章の序盤だ、要約どおりじっくり進めるしかない。<p></p><h4>真理値</h4><p>さて、真偽値である。truth valueの訳なら真理値であるが、真理の値ではまるで宗教である。これを対し、真偽値なら真か偽かの値というのが字面をみるだけでわかるので優れた用語といえる。</p><p>&nbsp;</p><p>しかし、ジャーゴンを使い人を煙に巻いてこその意識高い系なので、あえて真理値を使いたい。もっとも、boolean valueなので真理値とは違うかもしれない。</p><h4>正しい論理記号</h4><p>その他は、真理関数の連言が&amp;&amp;なのはともかく、選言が||なのは憶えにくい。あえてストロークを使う意味がわからない。とはいえ、歴史的に見ても論理記号の書き方は定まったものがないので慣れるしかない。</p><h3>感想の感想</h3><p>明らかに、うんちくを披露したいだけの後半が蛇足だ。しかし、このような関連性の低い話題に話を持ってくのが意識高い系であり、その自然さと強引さが腕の見せ所である。</p><h3>解答</h3><p>設問なし。</p>
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12567992748.html</link>
<pubDate>Sat, 25 Jan 2020 17:54:10 +0900</pubDate>
</item>
<item>
<title>プログラミングinOCaml　3.1の感想</title>
<description>
<![CDATA[ <h3>本文の感想</h3><p>アブストラクトの最後の行を読んでビビっていたが、この節はなんとかついていけそうだ。もっとも、分かってないからこそ疑問が生じていない可能性もあるが。</p><p>&nbsp;</p><p>ところで函数といえば、中学のとき、f(x) = x + 1と、そのxをzで置き換えたf(z) = z + 1とがなぜ等しいのか理解できなかった。</p><p>&nbsp;</p><p>今の知識で説明すると、ZFでの函数の存在を示す置換公理図式においては上式のxやzはダミー変数になるので、これらを置き換えても式の意味は同じである。したがって、函数の外延は同じものであり、同じ外延を持つものは同じオブジェクトである、ということになるだろう。</p><p>&nbsp;</p><p>この説明を中学生のときの自分にしても通用しない。なぜなら、中学で習った函数とはxからf(x)の値を計算するための方法のことだった。そのため、f(x)とf(z)とが等しいというためには、すべての実数x, zについてx=zならばf(x)=f(z)が成り立つことを示さなければならない。</p><p>これには、実数がどのようなオブジェクトであるのかと、その実数が群の公理のモデルであることを示す必要があるのだが、ZFで実数を定義する時点で函数の定義も変わってしまう。</p><p>何が言いたいのかというと、中学での定義のように、xにy(=f(x))を対応させる方法が関数である、とした場合、f(x)とf(z)とが等しいことは示せないのではないだろうか。</p><p>&nbsp;</p><p>本文3.1の定義を読むと、OCamlにおける関数は、ZFのそれよりは、中学のときの計算手順に近い感じがする。</p><p>そうすると、OCamlでは、f(x)とf(z)とは等しいと判断できないのだろうか。上の式のように、オブジェクトが有限のときに限れば原理的には可能であるが。</p><h3>解答</h3><p>設問なし。</p>
]]>
</description>
<link>https://ameblo.jp/i8am00/entry-12525826792.html</link>
<pubDate>Fri, 20 Sep 2019 00:00:00 +0900</pubDate>
</item>
</channel>
</rss>
