課題αは提出は不要ですが、証明を複数ファイルに分割する方法なので重要です。ぜひとも出来るようにしておきましょう。
ただし、出題の都合上、課題αの内容は他の問題を解くのには必要ないと思われます。
二つ以上のファイルからなる証明を用意し、コンパイルせよ。coq_makefileを使わない方法と使う方法がある。どちらか一方でもよいが、両方試すとよい。
例えば、次のような二つの証明を用意する。
Ternary.v
Delimit Scope tern_scope with tern.
Inductive tern := true | intermed | false.
Definition andt a b :=
match a, b with
| false, _ | _, false => false
| intermed, _ | _, intermed => intermed
| _, _ => true
end.
Notation "a && b" := (andt a b) : tern_scope.
TernaryProperties.v
Require Import Ternary.
Lemma andt_assoc a b c : (a && (b && c) = (a && b) && c)%tern.
Proof.
destruct a; destruct b; destruct c; reflexivity.
Qed.
コンパイルに成功したら、CoqIDEでこれらを編集できるか試してみよ。
例1) Ternary.vをコンパイルした上で、TernaryProperties.vをCoqIDE上で開き、最後まで証明が通ることを確認する。TernaryProperties.vを書き換えて、andtが可換であることの証明を書き加える。
例2) 例1に続いて、Ternary.vの内容を書き換えて、論理和演算を定義してみる。これをコンパイルし、TernaryProperties.vを開いているCoqIDE側でその内容をリロードする。その後、TernaryProperties.vに論理和演算に関する証明を書き加える。
この課題は提出不要だが、提出しても構わない。
ヒント
Sectionを使って、非空なリストを表すposlistを定義する。この定義を埋めよ。
(* Section の練習 *)
Section Poslist.
(* このセクションの中では、Aが共通の変数として使える。 *)
Variable A : Type.
(* 非空なリスト *)
Inductive poslist : Type := (* ここを埋める *) .
Section Fold.
(* 二項演算 *)
Variable g : A -> A -> A.
(* gによって畳み込む。
* 次のどちらかを定義すること。どちらでもよい。
* 左畳み込み : リスト [a; b; c] に対して (a * b) * c を計算する。
* 右畳み込み : リスト [a; b; c] に対して a * (b * c) を計算する。
*)
Definition fold : poslist -> A := (* ここに定義を書く *).
(* DefinitionをFixpointなどに置き換えてもよい。 *)
End Fold.
End Poslist.
(* Poslistから抜けたことにより、poslistは変数Aについて量化された形になる。 *)
(* このリストに関するmap関数 *)
Section PoslistMap.
Variable A B : Type.
Variable f : A -> B.
Definition map : poslist A -> poslist B := (* ここに定義を書く *)
End PoslistMap.
(* 今回は証明すべきことはないので、定義を正確に *)
定義を埋めたあと、それぞれの定義をPrintで出力してみよ。Sectionから抜ける前と後の違いを調べてみよ。(これについて書く必要はない。)
ヒント
半群とは、結合的な二項演算を持つ集合のことである。
次のソースを埋めて、自然数の乗算のなす半群と、自然数の最大値関数のなす半群を定義せよ。また、半群の直積を定義せよ。
G0とG1の(半群としての)直積とは、G0とG1の(集合としての)直積を台集合とし、二項演算は単に左側をG0の二項演算、右側をG1の二項演算で計算するものを入れたものである。
Require Import Arith.
Module Type SemiGroup.
Parameter G : Type.
Parameter mult : G -> G -> G.
Axiom mult_assoc :
forall x y z : G, mult x (mult y z) = mult (mult x y) z.
End SemiGroup.
Module NatMult_SemiGroup <: SemiGroup.
(* ここを埋める *)
End NatMult_SemiGroup.
Module NatMax_SemiGroup <: SemiGroup.
(* ここを埋める *)
End NatMax_SemiGroup.
Module SemiGroup_Product (G0 G1:SemiGroup) <: SemiGroup.
(* ここを埋める *)
End SemiGroup_Product.
ヒント
モジュールの練習です。モジュールは、名前空間としての用途の他に、このように構造の入った型を抽象化する働きもあります。
CoqのモジュールシステムはほぼOCamlのモジュールシステムと同じものです。OCamlのモジュールシステムは有用ですが、Coqのモジュールシステムは他のCoqの機能(ClassやCanonical Structure)で代替できることが多く、OCamlのそれと比べるとやや存在感が薄いかもしれません。
なお、Module Type中で用いられているParameterやAxiomは公理扱いではありません。
ヒント
モジュールへの機能の追加の練習です。標準ライブラリのCoq.Structuresの記述を参考にするとよいでしょう。
上記の半群の定義は、等号としてイコールを使っていた。これを改め、Coq.Structures.EqualitiesのEqualityTypeを用いるように書き換えよ。このとき、演算がEqualityTypeのeqに互換であること、すなわち forall x y z w, x == y -> z == w -> x * z == y * w を条件として課す必要があることに注意すること。
課題34で定義した半群について、半群Gが与えられたとき、Gの中心化半群を返すモジュールを定義せよ。Gの中心化半群とは、Gの全ての元と可換な元全体からなるGの部分半群である。