この投稿のシリーズでは、私達は小さなプログラミング言語を形式手法で定義します。その定義についてLeanを使い定理を証明します。
初めに
様々なプログラミング言語が存在しますが、多くには正式な定義はありません。言語の大半は、実装により定義されています。
実装で定義を
というプログラミング言語があるとすれば、言語の実装は、という言語のプログラムをインプットとして、による何らかのアウトプットを作り出し、もしくはを無効として拒絶するプログラムです。
それで、実装がを拒絶しなければ、は言語のプログラムだ、という定義を立てます。
しかし、言語には複数の実装があって、その実装らは同じプログラムに違う行動を取ったら、どちらの実装は本当に言語の定義だと言い切れますか。
仕様で定義を
この問題を解決する方法の一つは、言語の仕様を書くことです。この仕様は人間の言語で書かれています。仕様を参考にし、開発者らは実装を作り上げるのです。
C、C++、Go、JavaScript(最も正しい名前は ECMAScript)などの言語はこのように仕様されています。
数学で仕様を
しかし、言葉だけではなく数学でも仕様を書けます。このように仕様された言語の例はStandard ML、Pony、WebAssembly。
数学で言語を仕様することはたやすくできることでもないのかもしれませんが、そこにある利益が本当です。
まず、数学的な仕様は一義的で、曖昧では断じてありません。それに比べれば、人間言語だけで書かれた仕様は時に曖昧で分かりにくいです。
更に、形式手法を使えば、その仕様に関して定理が証明できます。これは、仕様にバグや誤りなどがないことを言い切れる証拠になります。
プログラミング言語を定義することで、この仕様の仕方を調べましょう。
「発言」という小さな言語
まずは言語に名をつけるのです。
プログラミング言語を実装することについて傑作であるブログがあります。作者がそのブログでしたように、英語の「utterance」という言葉を他の言語に翻訳することで、私達の言語を名付けるとしましょう。私自身の興味のある言語である日本語を目的の言語にします。従って私達の言語を「発言」と名付けておきましょう。
今のところ、発言には整数とブーリアンだけです。
整数をかかのような定数の式で表します。整数は無限なので、定数も無限です。整数の最大限などの実用的な配慮を今のところ無視します。
ブーリアンの真をで、偽をで表記します。
最後に、条件式を追加します:
これはまずを評価します。次に
- それはであればを評価し;
- それはであればを評価します。
発言は小さな言語であることは意図的です。言語その物がそれ程複雑ではないから、その言語を仕様する形式手法は少しでも慣れやすくなる、というのは目的です。
構文規則
BNFのような形式文法で式の構文規則を定義します。任意な型を、式をという変数で表します。
整数は無限で書くのは面倒になるから、は任意な整数だとします。
これは、という式が整数定数か、ブーリアン定数か、条件式だということです。
条件式には他の式、、が含まれていることを注意してください。
動的意味論
式をどう評価するかを定義します。これは動的意味論と言います。動的意味論の定義の仕方はいくつかありますが、私達は構造操作的意味論にします。
その為、判断を二つ作り上げます。判断は推測規則で定義されます。
値:
一つ目の判断は。「は値だ」と読みます。値というのは評価し終わった式のことを言います。
まず、整数定数は値です。この事実を推測規則で表記します。
推測規則は分数に見え、前提が上で一つの結論が下です。この規則には前提がないから線の上には何もありません。
ブーリアン定数も値だと、二個の規則で表します。
発言ではこれらだけが値です。しかし条件式はどうでしょう。
踏み出し:
値でない式をどう評価するかを定義します。
第二の動的意味論の判断であるは「が一歩を踏み出しになる」と読みます。
これで「式を評価する」というのは式が値になるまで新たな式へと踏み出すということになります。
発言では、唯一踏み出せる式は条件式です。まず、そのとの間にあるという式が踏み出すことができればそのを囲む条件式自体が他のやを変えずに踏み出せます。
そして、が値だったらどうするか定義します。だったらを無視しながらに踏み出します。
だったら逆にを無視しならがに踏み出します。
これで動的意味論の定義を完了したのです。
しかし問題が発生しました。
問題
先、式の評価を定義しました:
「式を評価する」というのは式が値になるまで新たな式へと踏み出すということになります。
しかしこの定義では評価できない式が存在してしまいます。例えば:
この式は踏み出せません。なぜならがかか踏み出せる場合だけ踏み出しを定義しました。が整数である場合、何も定義しなかったのです。
なのに、この式は値でもないのです。この式は嵌ったとしか言えません。
選択肢は二つあります。まずこのような式に対応する為、動的意味論に推測規則を追加する手があります。例えば次の規則で C 言語を真似します:
これはをとし、他の整数をとします。
二番目の手は「有効な式」を定義し、その有効な式だけを評価します。ここではその選択肢にします。
どの式が有効か定義する為、静的意味論を導入します。
静的意味論:
静的意味論は、有効な式ということを定義します。
まず、型というという概念を紹介します。今のところ型は整数とブーリアンです。
次、という判断を定義します。「の型はだ」という意味です。それで「有効な式」というのは、或る型が存在しが事実だということになります。
の規則を作り上げることにより定義します。整数定数の式の型は整数で、ブーリアンは同様です。
条件式は、の型はブーリアンであることを前提とします。との型は任意で同じというのも前提です。そしてその型は条件式の型になります。
の型はブーリアンだから先のような式はもう静的意味論により禁止されています:
これで静的意味論を完了しました。
定理
今になって、発言についての定理を宣言し証明できます。
まずは「進歩」の定理。進歩は、型のある式は値か踏み出せると言います。
For all and , if , then or there exists such that .
静的意味論を紹介する前、或る式は踏み出せないし、値でもないという問題がありました。しかし静的意味論を使い、定理の前提を強化し、定理を証明可能にするのです。
次は「維持」です。維持は、型のある式が踏み出せれば、その踏み出された式も同じ型を持つと言います。
For all and and , if and , then .
それらを合わせて次の「安全」定理の出来上がりです。
For all and , if , then or there exists such that and .
とりわけ注目して欲しいのは、の場合、も事実。これでまた安全定理をに使えます。
証明はGitHubにあります。
次の投稿では、関数を発言に追加します。