comparison agda.tex @ 57:5f0e13923cfd

Fixes
author Yasutaka Higa <e115763@ie.u-ryukyu.ac.jp>
date Mon, 16 Feb 2015 16:24:42 +0900
parents bf136bd59e7a
children
comparison
equal deleted inserted replaced
56:398b42a1ac19 57:5f0e13923cfd
3 第\ref{chapter:category}章では functor, natural transformation, monad の定義を行ない、第\ref{chapter:functional_programming}章では functional programming における対応を述べた。 3 第\ref{chapter:category}章では functor, natural transformation, monad の定義を行ない、第\ref{chapter:functional_programming}章では functional programming における対応を述べた。
4 その中で、 Functor 則や Monad 則といった満たすべき性質がいくつか存在した。 4 その中で、 Functor 則や Monad 則といった満たすべき性質がいくつか存在した。
5 functional programming において、あるデータ型と対応する計算が Functor 則を満たすかの保証は言語の実装に依存している。 5 functional programming において、あるデータ型と対応する計算が Functor 則を満たすかの保証は言語の実装に依存している。
6 例えば、 Haskell において functor は型クラスによって提供されるため、型レベルのチェックを行なう。 6 例えば、 Haskell において functor は型クラスによって提供されるため、型レベルのチェックを行なう。
7 そのため、型チェックは通るが Functor 則を満たさない functor が定義できてしまう。 7 そのため、型チェックは通るが Functor 則を満たさない functor が定義できてしまう。
8 よって Haskell において Delta Monad を定義しただけでは証明が存在しない。 8 よって Haskell において Delta Monad を定義しただけでは Delta Monad が Monad であるかの証明が存在しない。
9 そこで証明支援系言語 Agda を用いて、 Delta が Functor 則と Monad 則を満たすことを証明する。 9 そこで証明支援系言語 Agda を用いて、 Delta が Functor 則と Monad 則を満たすことを証明する。
10 10
11 第\ref{chapter:agda}章は Agda における証明手法について述べる。 11 第\ref{chapter:agda}章は Agda における証明手法について述べる。
12 12
13 % {{{ Natural Deduction 13 % {{{ Natural Deduction
51 \RightLabel{ $ \Rightarrow \mathcal{I} $} 51 \RightLabel{ $ \Rightarrow \mathcal{I} $}
52 \UnaryInfC{$ A \Rightarrow B $} 52 \UnaryInfC{$ A \Rightarrow B $}
53 \end{prooftree} 53 \end{prooftree}
54 54
55 そうすると、仮定 A は dead となり、新たな命題 $ A \Rightarrow B $ を導くことができる。 55 そうすると、仮定 A は dead となり、新たな命題 $ A \Rightarrow B $ を導くことができる。
56 A という仮定に依存して B を導く証明から、A が存在すれば B が存在するという証明を導いたこととなる。 56 A という仮定に依存して B を導く証明から、「A が存在すれば B が存在する」という証明を導いたこととなる。
57 このように、仮定から始めて最終的に全ての仮定を dead とすることで、仮定に依存しない証明を導くことができる。 57 このように、仮定から始めて最終的に全ての仮定を dead とすることで、仮定に依存しない証明を導くことができる。
58 58 なお、dead な仮定は \verb/[A]/ のように \verb/[]/ で囲んで書く。
59 alive な仮定を dead にすることができるのは $ \Rightarrow I $ 規則のみである。 59
60 alive な仮定を dead にすることができるのは $ \Rightarrow \mathcal{I} $ 規則のみである。
60 それを踏まえ、 natural deduction には以下のような規則が存在する。 61 それを踏まえ、 natural deduction には以下のような規則が存在する。
61 62
62 \begin{itemize} 63 \begin{itemize}
63 \item Hypothesis 64 \item Hypothesis
64 65
207 208
208 「A は B であり、 B は C である。よって A は C である」 が証明するべき命題である。 209 「A は B であり、 B は C である。よって A は C である」 が証明するべき命題である。
209 まず、「A は B であり」から、Aから性質Bが導けることが分かる。これが $ A \Rightarrow B $ となる。 210 まず、「A は B であり」から、Aから性質Bが導けることが分かる。これが $ A \Rightarrow B $ となる。
210 次に、「B は C である」から、Bから性質Cが導けることが分かる。これが $ B \Rightarrow C $ となる。 211 次に、「B は C である」から、Bから性質Cが導けることが分かる。これが $ B \Rightarrow C $ となる。
211 そしてこの2つは同時に成り立つ。 212 そしてこの2つは同時に成り立つ。
212 よって $ (A \Rightarrow B) \land (B \Rightarrow C)$ が前提となる。 213 よって $ (A \Rightarrow B) \land (B \Rightarrow C)$ が仮定となる。
213 この条件2つが成り立つ時に「Aは Cである」が成りたつ。 214 この仮定が成り立つ時に「Aは Cである」を示せば良い。
214 条件と同じように「A は C である」は、 $ A \Rightarrow C $ と書けるため、証明するべき論理式は $ ((A \Rightarrow B) \land (B \Rightarrow C)) \Rightarrow (A \Rightarrow C) $ になる。 215 仮定と同じように「A は C である」は、 $ A \Rightarrow C $ と書けるため、証明するべき論理式は $ ((A \Rightarrow B) \land (B \Rightarrow C)) \Rightarrow (A \Rightarrow C) $ となる。
215 216
216 証明の手順はこうである。 217 証明の手順はこうである。
217 まず条件$ (A \Rightarrow B) \land (B \Rightarrow C)$とAを2つ仮定する。 218 まず条件$ (A \Rightarrow B) \land (B \Rightarrow C)$とAの2つを仮定する。
218 条件を $ \land 1 \mathcal{E} $ $ \land 2 \mathcal{E} $ により分解する。 219 条件を $ \land 1 \mathcal{E} $ $ \land 2 \mathcal{E} $ により分解する。
219 A と $ A \Rightarrow B$ から B を、 B から $ B \Rightarrow C $ から C を導く。 220 A と $ A \Rightarrow B$ から B を、 B と $ B \Rightarrow C $ から C を導く。
220 ここで $ \Rightarrow \mathcal{I} $ により $ A \Rightarrow C $ を導く。 221 ここで $ \Rightarrow \mathcal{I} $ により $ A \Rightarrow C $ を導く。
221 この際に dead にする仮定は A である。 222 この際に dead にする仮定は A である。
222 そのために $_{(1)} $ と対応する \verb/[]/の記号に数値を付けてある。 223 数回仮定を dead にする際は $_{(1)} $ のように対応する \verb/[]/の記号に数値を付ける。
223 これで残る仮定は $ (A \Rightarrow B) \land (B \Rightarrow C)$ となり、これから $ A \Rightarrow C $ を導くことができたためにさらに $ \Rightarrow \mathcal{I} $ を適用する。 224 これで残る alive な仮定は $ (A \Rightarrow B) \land (B \Rightarrow C)$ となり、これから $ A \Rightarrow C $ を導くことができたためにさらに $ \Rightarrow \mathcal{I} $ を適用する。
224 結果、証明すべき論理式$ ((A \Rightarrow B) \land (B \Rightarrow C)) \Rightarrow (A \Rightarrow C) $ が導けたために証明終了となる。 225 結果、証明すべき論理式$ ((A \Rightarrow B) \land (B \Rightarrow C)) \Rightarrow (A \Rightarrow C) $ が導けたために証明終了となる。
225 226
226 % }}} 227 % }}}
227 228
228 % {{{ Curry-Howard Isomorphism 229 % {{{ Curry-Howard Isomorphism
255 プログラムにおいて、変数 x は内部の値により型が決定される。 256 プログラムにおいて、変数 x は内部の値により型が決定される。
256 特に、x の値が未定である場合は未定義の変数としてエラーが発生する。 257 特に、x の値が未定である場合は未定義の変数としてエラーが発生する。
257 しかし、 x を取って x を返す関数は定義することはできる。 258 しかし、 x を取って x を返す関数は定義することはできる。
258 これは natural deduction の $ \Rightarrow \mathcal{I} $ により仮定を discharge することに相当する。 259 これは natural deduction の $ \Rightarrow \mathcal{I} $ により仮定を discharge することに相当する。
259 260
260 このように、 natural deduction における証明はそのまま 型付き $ \lambda $ 計算にエンコードすることができる。 261 このように、 natural deduction における証明はそのまま 型付き $ \lambda $ 計算に変換することができる。
261 262
262 それぞれの詳細な対応は省略するが、表\ref{tbl:curry_howard_isomorphism} のような対応が存在する。 263 それぞれの詳細な対応は省略するが、表\ref{tbl:curry_howard_isomorphism} のような対応が存在する。
263 264
264 \begin{center} 265 \begin{center}
265 \begin{table}[htbp] 266 \begin{table}[htbp]
273 \caption{natural deuction と 型付き $ \lambda $ 計算との対応} 274 \caption{natural deuction と 型付き $ \lambda $ 計算との対応}
274 \label{tbl:curry_howard_isomorphism} 275 \label{tbl:curry_howard_isomorphism}
275 \end{table} 276 \end{table}
276 \end{center} 277 \end{center}
277 278
278 \ref{section:natural_deduction}節でも行なった三段論法の証明を Haskell により行なうとリスト\ref{src:modus_ponens} 279 \ref{section:natural_deduction}節でも行なった三段論法の証明を Haskell により行なうとリスト\ref{src:modus_ponens}となる。
279 280
280 \begin{table}[html] 281 \begin{table}[html]
281 \lstinputlisting[label=src:modus_ponens, caption=Haskell における三段論法の証明] {src/modus_ponens.txt} 282 \lstinputlisting[label=src:modus_ponens, caption=Haskell における三段論法の証明] {src/modus_ponens.txt}
282 \end{table} 283 \end{table}
283 284
304 305
305 \section{Agda による証明} 306 \section{Agda による証明}
306 \label{section:agda} 307 \label{section:agda}
307 \ref{section:curry_howard_isomorphism}節において型を用いて証明を行なう手法を述べた。 308 \ref{section:curry_howard_isomorphism}節において型を用いて証明を行なう手法を述べた。
308 しかし、Haskell における型システムは証明を記述するために用いるものではない。 309 しかし、Haskell における型システムは証明を記述するために用いるものではない。
309 よって、依存型を持つ証明支援言語 Agda を用いて証明を記述していく。 310 よって、依存型を持つ証明支援言語 Agda を用いて証明を記述する。
310 311
311 依存型とは値に依存した型を作ることができる型であり、非常に表現能力が高い。 312 依存型とは値に依存した型を作ることができる型であり、非常に表現能力が高い。
312 値に型を使うことができるために証明に基づいた証明を記述することができる。 313 値に型を使うことができるために証明に基づいた証明を記述することができる。
313 314
314 $ \Rightarrow \mathcal{E} $ に対応する関数適用を Agda で記述するとリスト\ref{src:apply_function_in_agda}のようになる。 315 $ \Rightarrow \mathcal{E} $ に対応する関数適用を Agda で記述するとリスト\ref{src:apply_function_in_agda}のようになる。
344 \begin{table}[html] 345 \begin{table}[html]
345 \lstinputlisting[label=src:product, caption=Agdaにおける直積型の例] {src/product.agda.replaced} 346 \lstinputlisting[label=src:product, caption=Agdaにおける直積型の例] {src/product.agda.replaced}
346 \end{table} 347 \end{table}
347 348
348 関数の定義時に \verb/_/ とした部分には項を入れることで関数が適用される。 349 関数の定義時に \verb/_/ とした部分には項を入れることで関数が適用される。
349 つまり \verb/_x_/ とすれば中置関数を作成することができる。 350 つまり \verb/_/$ \times $\verb/_/ とすれば中置関数を作成することができる。
350 データ型 \verb/_x_/ は型 A と B を持つ型である。 351 データ型 \verb/_/$ \times $\verb/_/ は型 A と B を持つ型である。
351 データ型 \verb/_x_/ はコンストラクタ \verb/<_,_>/ により構成され、コンストラクタは A と B を取ることで \verb/A x B/ 型を返す。 352 データ型 \verb/_/$ \times $\verb/_/ はコンストラクタ \verb/<_,_>/ により構成され、コンストラクタは A と B を取ることで $ A \times B $ 型を返す。
352 353
353 例えば型A と B から 直積型 $ A \times B $ が作成できる証明は constructProduct である。 354 例えば型A と B から 直積型 $ A \times B $ が作成できる証明は constructProduct である。
354 任意の型AとBを受けとり、コンストラクタ \verb/<_,_>/を用いて $ A \times B $ に相当する \verb/A x B/を返す。 355 任意の型AとBを受けとり、コンストラクタ \verb/<_,_>/を用いて $ A \times B $ に相当する値を返す。
355 356
356 また、型に対応するコンストラクタはパターンマッチにより分解することができる。 357 また、コンストラクタは引数にてパターンマッチにより分解することができる。
357 その例が patternMatchProduct である。 358 その例が patternMatchProduct である。
358 受けとる引数の型は \verb/ A x B/ であるため、ありえるコンストラクタは \verb/<_,_>/のみである。 359 受けとる引数の型は $ A \times B $ であるため、ありえるコンストラクタは \verb/<_,_>/のみである。
359 よって引数を取る際に \verb/< a , b >/ のように対応するコンストラクタと変数を用意することで、コンストラクタに基づいて型を分解することができる。 360 よって引数を取る際に \verb/< a , b >/ のように対応するコンストラクタと変数を用意することで、コンストラクタに基づいて値を分解することができる。
360 \verb/A x B/ 型から B を取るため、\verb/A x B/ 型の変数を直接束縛せずにコンストラクタで分解し、a と b に束縛することで A と B が得られる。 361 $ A \times B$ 型から B を取るために、$ A \times B$ 型の引数を変数にを直接束縛せずにコンストラクタで分解し、a と b に束縛することで A と B を得る。
362 b を返すことで型 B の値を返すことができる。
361 そのため、 patternMathProduct は $ \land 2 \mathcal{E} $ そのものである。 363 そのため、 patternMathProduct は $ \land 2 \mathcal{E} $ そのものである。
362 364
363 % }}} 365 % }}}
364 366
365 % {{{ Reasoning 367 % {{{ Reasoning
410 \lstinputlisting[label=src:nat_add, caption=Agdaにおける自然数型に対する加算の定義] {src/nat_add.agda} 412 \lstinputlisting[label=src:nat_add, caption=Agdaにおける自然数型に対する加算の定義] {src/nat_add.agda}
411 \end{table} 413 \end{table}
412 414
413 加算は中置関数 \verb/_+_/ として定義する。 415 加算は中置関数 \verb/_+_/ として定義する。
414 2つの Nat を取り、Natを返す。 416 2つの Nat を取り、Natを返す。
415 パターンマッチにより処理を変える。 417 関数 \verb/_+_/ はパターンマッチにより処理を変える。
416 0に対して m 加算する場合は m であり、 n の後続数に対して m 加算する場合は n に m 加算した数の後続数とする。 418 0に対して m 加算する場合は m であり、 n の後続数に対して m 加算する場合は n に m 加算した数の後続数とする。
417 S を左の数から右の数へ1つずつ再帰的に移していくような加算である。 419 S を左の数から右の数へ1つずつ再帰的に移していくような加算である。
418 420
419 例えば 3 + 1 といった計算は (S (S (S O))) + (S O) のように記述される。 421 例えば 3 + 1 といった計算は (S (S (S O))) + (S O) のように記述される。
420 ここで 3 + 1 が 4と等しいことの証明を行なう。 422 ここで 3 + 1 が 4と等しいことの証明を行なう。
422 等式の証明には agda の standard library における Relation.Binary.Core の定義を用いる。 424 等式の証明には agda の standard library における Relation.Binary.Core の定義を用いる。
423 425
424 \begin{table}[html] 426 \begin{table}[html]
425 \lstinputlisting[label=src:equiv, caption= Relation.Binary.Core による等式を示す型 $ \equiv $] {src/equiv.agda.replaced} 427 \lstinputlisting[label=src:equiv, caption= Relation.Binary.Core による等式を示す型 $ \equiv $] {src/equiv.agda.replaced}
426 \end{table} 428 \end{table}
427 等式は等式を示すデータ型 $ \equiv $ により定義される。 429 Agda において等式は、等式を示すデータ型 $ \equiv $ により定義される。
428 $ \equiv $ は同じ両辺が同じ項に簡約される時にコンストラクタ refl で構築できる。 430 $ \equiv $ は同じ両辺が同じ項に簡約される時にコンストラクタ refl で構築できる。
429 431
430 実際に 3 + 1 = 4 の証明は refl で構成できる(リスト\ref{src:three_plus_one})。 432 実際に 3 + 1 = 4 の証明は refl で構成できる(リスト\ref{src:three_plus_one})。
431 433
432 \begin{table}[html] 434 \begin{table}[html]
474 この等式は + の定義により $ O + (S m) \equiv S (m + O) $ と変形できる。 476 この等式は + の定義により $ O + (S m) \equiv S (m + O) $ と変形できる。
475 $ S (m + O) $ は $ m + O $ に S を加えたものであるため、 cong を用いて再帰的に \verb/addSym/ を実行することで証明できる。 477 $ S (m + O) $ は $ m + O $ に S を加えたものであるため、 cong を用いて再帰的に \verb/addSym/ を実行することで証明できる。
476 478
477 この2つの証明はこのような意味を持つ。 479 この2つの証明はこのような意味を持つ。
478 n が 0 であるとき、 m も 0 なら簡約により等式が成立する。 480 n が 0 であるとき、 m も 0 なら簡約により等式が成立する。
479 n が 0 であるとき、 m が 0 でないとき、 m は後続数である。 481 n が 0 であり、 m が 0 でないとき、 m は後続数である。
480 よって m が (S x) と書かれる時、 x は m の前の値である。 482 よって m が (S x) と書かれる時、 x は m の前の値である。
481 前の値による交換法則を用いてからその結果の後続数も + の定義により等しい。 483 前の値による交換法則を用いてからその結果の後続数も + の定義により等しい。
484
482 ここで、 \verb/addSym/ に渡される m は1つ値が減っているため、最終的には n = 0, m = 0 である refl にまで簡約され、等式が得られる。 485 ここで、 \verb/addSym/ に渡される m は1つ値が減っているため、最終的には n = 0, m = 0 である refl にまで簡約され、等式が得られる。
483 486
484 \item n = S n, m = O 487 \item n = S n, m = O
485 488
486 $ (S n) + O \equiv O + (S n) $ を証明する。 489 $ (S n) + O \equiv O + (S n) $ を証明する。
525 addToRight の証明の解説は省略する。 528 addToRight の証明の解説は省略する。
526 addToRight を用いることで \verb/S ((S m) + n)/ から \verb/(S m) + (S n)/を得られた。 529 addToRight を用いることで \verb/S ((S m) + n)/ から \verb/(S m) + (S n)/を得られた。
527 これで等式 $ (S m) + (S n) \equiv (S n) + (S m) $ の証明が完了した。 530 これで等式 $ (S m) + (S n) \equiv (S n) + (S m) $ の証明が完了した。
528 531
529 自然数に対する + の演算を考えた時にありえるコンストラクタの組み合せ4パターンのいずれかでも交換法則の等式が成り立つことが分かった。 532 自然数に対する + の演算を考えた時にありえるコンストラクタの組み合せ4パターンのいずれかでも交換法則の等式が成り立つことが分かった。
530 また、定義した + の演算のみでは加法の交換法則は証明できず、さらに等式を証明する必要があった。
531
532 このように、Agda における等式の証明は、定義や等式を用いて右辺と左辺を同じ項に変形することで行なわれる。 533 このように、Agda における等式の証明は、定義や等式を用いて右辺と左辺を同じ項に変形することで行なわれる。
533 534
534 % }}} 535 % }}}