Agda 入門
Yasutaka Higa
Agda 入門
このセミナーの目的
証明支援系の言語である Agda の入門を目的としています
具体的には
Agda による証明の方法を知る
実際に自然数の加算の交換法則の証明を追う
セミナーについて必要する事前知識
なお、このセミナーについては
C や Java によるプログラミング言語を書いたことがある
関数や引数、型といった単語の詳細は省略することがあります
数学における述語論理
P ならば Q といった論理
といったことを前提条件としています
Agda とはどういう言語なのか
証明支援系と呼ばれる分野の言語です
他には Coq などがあります
Haskell で実装されています
dependent type の言語 です
型から生成さえれた型を扱える
いわゆる「強い静的型付け」などと言われる種類です
型と証明との対応 : Curry-Howard Isomorphism
Agda における証明は
証明したい命題 == 関数の型
命題の証明 == 関数の定義
として定義します。
関数と命題の対応を Curry-Howard Isomorphism と言います
‘A ならば B’ と ‘A’ が成り立つなら ‘B’
Agda において
apply : A -> (A -> B) -> B
apply a f = f a
と記述します
Agda のSyntax
apply : A -> (A -> B) -> B
apply a f = f a
関数名 : 型
関数名 <引数,,,> = 定義
Agda の型のSyntax
apply : A -> (A -> B) -> B
引数の型 -> 返り値の型
結合は右結合です。なのでこのようになります
A -> ((A -> B) -> B)
右結合のため、A を受けとって ((A -> B) -> B) を返す、とも読めます
Agda の型のSyntax : 複数の引数
複数の引数は
Arg1Type -> Arg2Type -> ReturnType
のように書きますが、右結合により
Arg1Type -> (Arg2Type -> ReturnType)
となり、引数は1つしかないと考えることができます。
これを Curry 化と言い、引数が複数の場合を考えずに良くなります
関数の定義を C の Syntax 書くと
apply : A -> (A -> B) -> B
B apply(A a, B ( * f )(A))
これを満たす定義を関数applyの実装として書けば良い
証明 == 正しい返り値を返す なので
つまりコンパイルを通してしまえば良い
Agda で書いてみると
emacs から使うと良いです
module < filename > where
を先頭に書く必要があります
証明を定義していく
C-c C-l で型チェック(証明チェック)ができます
Agda による apply
apply : A -> (A -> B) -> B
apply a f = f a
とは
A を Int, B を String とすると
Int と、 Int から String を返す関数があれば String を作れる
と読めます。つまり関数適用です
命題に ‘ならば’ を含む場合
関数を返せば良いです
Agda には lambda があるので
id : (A -> A)
id = \a -> a
といったように書けます。
lambda の syntax は \arg -> body です
‘ならば’ を含む証明
三段論法 の証明
compose : (A -> B) -> (B -> C) -> (A -> C)
compose f g = \a -> g (f a)
三段論法は関数の合成に相当しています
Agda による 証明 の方法のまとめ
型として (仮定) -> (仮定) -> … -> (命題)
として命題を定義
それを満たす定義を関数として定義する
自然数の加算の交換法則の証明
まずは自然数を定義する
ペアノ算術を使います
ペアノ算術による自然数の定義
ゼロは自然数である
自然数の後続数は自然数である
TODO: 詳細は今から
ペアノ算術の Agda による定義
data type を定義します
data Int where
O -> Int
S -> Int -> Int
Int は O か、 Int に S をかけたもの、とします
パターンマッチ
Agda においてはデータ型を引数で分解することができます
ある型に続している値が、どのコンストラクタにおいて構成されたかをパターンで示せます
これをパターンマッチと言います
double : Int -> Int
double O = O
double (S n) = S (S (double n))
関数名 (引数のパターン) = 定義
パターンマッチによる自然数の加算の定義
TODO: 今から
‘等しさ’ ということ
交換法則においては ‘等しい’ ということを証明しなければなりません
等しい、ということも定義する必要があります
命題は型で定義するため、’等しい’、という型が必要です
等しさをデータ型で定義する
== を定義していきます
== は型でなくてはならないので
data
==
: {A : Set} -> A -> A -> Set where
となります
よって、 hoge と fuga の等しさを証明したい場合は
‘hoge == fuga’ 、という型を持つ項を関数の定義に書くことが証明になります
‘等しい’ということの定義3つ
TODO: refl, sym, cong を書きます
comment
個人的には Relation.Binary.PropositionalEquality を open import するよりは自前で定義したい
あと R とか reasoning もできれば使いたくない
というか必要でないなら積極的に削っていかないと時間がおそらく足りない
時間あまった時用に証明をもう1,2 個くらい書いておきたい
交換法則を命題として定義する
== を用いて
(n : Int) -> (m : Int) -> n + m == m + n
引数は (名前 : 型) として名前付けできます
交換法則を証明する
交換法則を関数の定義として書いていきます
TODO: 今から
Agda による証明方法のまとめ
関数の型を命題、関数の定義を証明とする
命題を扱う必要があるため、型もデータ型として定義できる
データ型はパターンマッチにより分解することができる
C-c C-l により型のチェックが成功すれば証明終了