Mercurial > hg > Papers > 2017 > atton-master
comparison paper/agda.tex @ 80:73da47f32888
Update summary
author | atton <atton@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 08 Feb 2017 17:25:27 +0900 |
parents | 4985359bd08b |
children | c0199291c58e |
comparison
equal
deleted
inserted
replaced
79:4985359bd08b | 80:73da47f32888 |
---|---|
8 証明を行なう機構として注目したのが型システムである。 | 8 証明を行なう機構として注目したのが型システムである。 |
9 | 9 |
10 型システムは Curry-Howard 同型対応により命題と型付きラムダ計算が一対一に対応する。 | 10 型システムは Curry-Howard 同型対応により命題と型付きラムダ計算が一対一に対応する。 |
11 依存型という型を持つ証明支援系言語 Agda を用いて型システムで証明が行なえることを示す。 | 11 依存型という型を持つ証明支援系言語 Agda を用いて型システムで証明が行なえることを示す。 |
12 | 12 |
13 % {{{ 型システムとは TODO: もう少し大ざっぱに説明 | 13 % {{{ 型システムとは |
14 \section{型システムとは} | 14 \section{型システムとは} |
15 型システムとは、計算する値を分類することにでプログラムがある種の振舞いを行なわないことを保証する機構の事である\cite{Pierce:2002:TPL:509043}\cite{pierce2013型システム入門プログラミング言語と型の理論}。 | 15 型システムとは、計算する値を分類することにでプログラムがある種の振舞いを行なわないことを保証する機構の事である\cite{Pierce:2002:TPL:509043}\cite{pierce2013型システム入門プログラミング言語と型の理論}。 |
16 ある種の振舞いとはプログラム中の評価不可能な式や、言語として未定義な式などが当て嵌まる。 | 16 ある種の振舞いとはプログラム中の評価不可能な式や、言語として未定義な式などが当て嵌まる。 |
17 例えば、gcc や clang といったコンパイラは関数定義時に指定された引数の型と呼び出し時の値の型が異なる時に警告を出す。 | 17 例えば、gcc や clang といったコンパイラは関数定義時に指定された引数の型と呼び出し時の値の型が異なる時に警告を出す。 |
18 この警告は関数が受けつける範囲以外の値をプログラマが渡してしまった場合などに有効に働く。 | 18 この警告は関数が受けつける範囲以外の値をプログラマが渡してしまった場合などに有効に働く。 |
52 例えば C言語では数値と文字を二項演算子 \verb/+/ で加算できるが、Haskell では加算することができない。 | 52 例えば C言語では数値と文字を二項演算子 \verb/+/ で加算できるが、Haskell では加算することができない。 |
53 これは Haskell が C言語よりも厳密な型システムを採用しているからである。 | 53 これは Haskell が C言語よりも厳密な型システムを採用しているからである。 |
54 具体的には Haskell は暗黙的な型変換を許さず、 C 言語は言語仕様として暗黙の型変換を持っている。 | 54 具体的には Haskell は暗黙的な型変換を許さず、 C 言語は言語仕様として暗黙の型変換を持っている。 |
55 | 55 |
56 型システムを定義することはプログラミング言語がどのような特徴を持つかを決めることにも繋がる。 | 56 型システムを定義することはプログラミング言語がどのような特徴を持つかを決めることにも繋がる。 |
57 | |
58 % }}} | |
59 | |
60 % {{{ 依存型を持つ証明支援系言語 Agda | |
61 | |
62 \section{依存型を持つ証明支援系言語 Agda} | |
63 型システムを用いて証明を行なうことができる言語に Agda~\cite{agda} が存在する。 | |
64 Agda は依存型という強力な型システムを持っている。 | |
65 依存型とは型も第一級オブジェクトとする型システムであり、型の型や型を引数に取る関数、値を取って型を返す関数などが記述できる。 | |
66 この節では Agda の文法的な紹介を行なう~\cite{Norell:2009:DTP:1481861.1481862}~\cite{agda-documentation}。 | |
67 | |
68 Agda はインデントに意味を持つ言語であるため、インデントはきちんと揃える必要がある。 | |
69 また、非常に多くの記号を利用できる言語であり、スペースの有無は厳格にチェックされる。 | |
70 なお、 \verb/--/ の後はコメントである。 | |
71 | |
72 まず、Agda のプログラムを記述するファイルを作成する。 | |
73 Agda のプログラムは全てモジュール内部に記述されるため、まずはトップレベルにモジュールを定義する必要がある。 | |
74 トップレベルのモジュールはファイル名と同一となる。 | |
75 例えば \verb/AgdaBasics.agda/ を作成する時のモジュール名はリスト~\ref{src:agda-module}のように定義する。 | |
76 | |
77 \lstinputlisting[label=src:agda-module, caption=Agdaのモジュールの定義する] {src/AgdaBasics.agda} | |
78 | |
79 Agda における型指定は $:$ を用いて行なう。 | |
80 例えば、変数xが型Aを持つ、ということを表すには \verb/x : A/ と記述する。 | |
81 | |
82 データ型は Haskell や ML に似た代数的なデータ構造である。 | |
83 データ型の定義は \verb/data/ キーワードを用いる。 | |
84 \verb/data/キーワードの後に \verb/where/ 句を書きインデントを深くした後、値にコンストラクタとその型を列挙する。 | |
85 例えば Bool 型を定義するとリスト~\ref{src:agda-bool}のようになる。 | |
86 Bool はコンストラクタ \verb/true/ か \verb/false/ を持つデータ型である。 | |
87 Bool 自身の型は \verb/Set/ であり、これは Agda が組み込みで持つ「型の型」である。 | |
88 Set は階層構造を持ち、型の型の型を指定するには Set1 と書く。 | |
89 | |
90 \lstinputlisting[label=src:agda-bool, caption=Agdaにおけるデータ型 Bool の定義] {src/AgdaBool.agda} | |
91 | |
92 | |
93 関数の定義は Haskell に近い。 | |
94 関数名と型を記述した後に関数の本体を \verb/=/ の後に指定する。 | |
95 関数の型は $ \rightarrow $ を用いる。 | |
96 なお、$\rightarrow$に対しては糖衣構文 \verb/->/ も用意されている。 | |
97 例えば引数が型 \verb/A/ で返り値が型 \verb/B/ の関数は \verb/A -> B/ のように書ける。 | |
98 Bool 変数 \verb/x/ を取って true を返す関数 \verb/f/はリスト~\ref{src:agda-function}のようになる。 | |
99 | |
100 \lstinputlisting[label=src/agda-function, caption=Agda における関数定義] {src/AgdaFunction.agda} | |
101 | |
102 引数は変数名で受けることもできるが、具体的なコンストラクタを指定することでそのコンストラクタが渡された時の挙動を定義できる。 | |
103 これはパターンマッチと呼ばれ、コンストラクタで case 文を行なっているようなものである。 | |
104 例えば Bool 型の値を反転する \verb/not/ 関数を書くとリスト~\ref{src:agda-not}のようになる。 | |
105 | |
106 \lstinputlisting[label=src:agda-not, caption=Agdaにおける関数 not の定義] {src/AgdaNot.agda} | |
107 | |
108 パターンマッチは全てのコンストラクタのパターンを含まなくてはならない。 | |
109 例えば、Bool 型を受け取る関数で \verb/true/ の時の挙動のみを書くことはできない。 | |
110 なお、コンストラクタをいくつか指定した後に変数で受けると、変数が持ちうる値は指定した以外のコンストラクタとなる。 | |
111 例えばリスト~\ref{src:agda-pattern}の not は x には true しか入ることは無い。 | |
112 なお、マッチした値を変数として利用しない場合は \verb/_/ を用いて捨てることもできる。 | |
113 | |
114 \lstinputlisting[label=src:agda-pattern, caption=Agdaにおけるパターンマッチ] {src/AgdaPattern.agda} | |
115 | |
116 関数にはリテラルが存在し、関数名を定義せずともその場で生成することができる。 | |
117 これをラムダ式と呼び、\verb/\arg1 arg2 -> function body/ のように書く。 | |
118 例えば Bool 型の引数 \verb/b/ を取って not を適用する \verb/not-apply/ をラムダ式で書くとリスト~\ref{src:agda-lambda}のようになる。 | |
119 関数 \verb/not-apply/ をラムダ式を使わずに定義すると \verb/not-apply-2/ になるが、この二つの関数は同一の動作をする。 | |
120 | |
121 \lstinputlisting[label=src:agda-lambda, caption=Agda におけるラムダ式] {src/AgdaLambda.agda} | |
122 | |
123 Agda では特定の関数内のみで利用する関数を \verb/where/ 句で記述できる。 | |
124 これは関数内部の冗長な記述を省略するのに活用できる。 | |
125 スコープは \verb/where/句が存在する関数内部のみであるため、名前空間が汚染させることも無い。 | |
126 例えば自然数3つを取ってそれぞれ3倍して加算する関数 \verb/f/ を定義するとき、 \verb/where/ を使うとリスト~\ref{src:agda-where} のように書ける。 | |
127 これは \verb/f'/ と同様の動作をする。 | |
128 \verb/where/ 句は利用したい関数の末尾にインデント付きで \verb/where/ キーワードを記述し、改行の後インデントをして関数内部で利用する関数を定義する。 | |
129 | |
130 \lstinputlisting[label=src:agda-where, caption=Agda における where 句] {src/AgdaWhere.agda} | |
131 | |
132 | |
133 データ型のコンストラクタには自分自身の型を引数に取ることもできる(リスト~\ref{src:agda-nat})。 | |
134 自然数のコンストラクタは2つあり、片方は自然数ゼロ、片方は自然数を取って後続数を返すものである。 | |
135 例えば0 は \verb/zero/ であり、1 は \verb/suc zero/に、3は \verb/suc (suc (suc zero))/ に対応する。 | |
136 | |
137 \lstinputlisting[label=src:agda-nat, caption=Agdaにおける自然数の定義] {src/AgdaNat.agda} | |
138 | |
139 自然数に対する演算は再帰関数として定義できる。 | |
140 例えば自然数どうしの加算は二項演算子\verb/+/としてリスト~\ref{src:agda-plus}のように書ける。 | |
141 | |
142 この二項演算子は正確には中置関数である。 | |
143 前置や後置で定義できる部分を関数名に \verb/_/ として埋め込んでおくことで、関数を呼ぶ時にあたかも前置や後置演算子のように振る舞う。 | |
144 例えば \verb/!_/ 関数を定義すると \verb/! true/ のように利用でき、\verb/_~/ 関数を定義すると \verb/false ~/ のように利用できる。 | |
145 | |
146 また、Agda は再帰関数が停止するかを判定できる。 | |
147 この加算の二項演算子は左側がゼロに対しては明らかに停止する。 | |
148 左側が1以上の時の再帰時には \verb/suc n/ から \verb/n/へと減っているため、再帰で繰り返し減らすことでいつかは停止する。 | |
149 もし \verb/suc n/ のまま自分自身へと再帰した場合、Agda は警告を出す。 | |
150 | |
151 \lstinputlisting[label=src:agda-plus, caption=Agda における自然数の加算の定義] {src/AgdaPlus.agda} | |
152 | |
153 次に依存型について見ていく。 | |
154 依存型で最も基本的なものは関数型である。 | |
155 依存型を利用した関数は引数の型に依存して返す型を決定できる。 | |
156 | |
157 Agda で \verb/(x : A) -> B/ と書くと関数は型 A を持つx を受け取り、Bを返す。 | |
158 ここで B の中で x を扱っても良い。 | |
159 例えば任意の型に対する恒等関数はリスト~\ref{src:agda-id}のように書ける。 | |
160 | |
161 \lstinputlisting[label=src:agda-id, caption=依存型を持つ関数の定義] {src/AgdaId.agda} | |
162 | |
163 この恒等関数 \verb/identitiy/ は任意の型に適用可能である。 | |
164 実際に関数 \verb/identitiy/ を Nat へ適用した例が \verb/identitiy-zero/ である。 | |
165 | |
166 多相の恒等関数では型を明示的に指定せずとも \verb/zero/ に適用した場合の型は自明に \verb/Nat -> Nat/である。 | |
167 Agda はこのような推論をサポートしており、推論可能な引数は省略できる。 | |
168 推論によって解決される引数を暗黙的な引数(implicit arguments) と言い、記号 \verb/{}/ でくくる。 | |
169 | |
170 例えば、\verb/identitiy/ の対象とする型\verb/A/を暗黙的な引数として省略するとリスト~\ref{src:agda-implicit-id}のようになる。 | |
171 この恒等関数を利用する際は特定の型に属する値を渡すだけでその型が自動的に推論される。 | |
172 よって関数を利用する際は \verb/id-zero/ のように型を省略して良い。 | |
173 なお、関数の本体で暗黙的な引数を利用したい場合は \verb/{variableName}/ で束縛することもできる(\verb/id'/ 関数)。 | |
174 適用する場合も \verb/{}/でくくり、\verb/id-true/のように使用する。 | |
175 | |
176 \lstinputlisting[label=src:agda-implicit-id, caption=Agdaにおける暗黙的な引数を持つ関数] {src/AgdaImplicitId.agda} | |
177 | |
178 Agda には C における構造体に相当するレコード型も存在する。 | |
179 定義を行なう際は \verb/record/キーワードの後にレコード名、型、\verb/where/ の後に \verb/field/ キーワードを入れた後、フィールド名と型名を列挙する。 | |
180 例えば x と y の二つの自然数からなるレコード \verb/Point/ を定義するとリスト~\ref{src:agda-record}のようになる。 | |
181 レコードを構築する際は \verb/record/ キーワードの後の \verb/{}/ の内部に \verb/fieldName = value/ の形で値を列挙していく。 | |
182 複数の値を列挙する際は \verb/;/ で区切る。 | |
183 | |
184 \lstinputlisting[label=src:agda-record, caption=Agdaにおけるレコード型の定義] {src/AgdaRecord.agda} | |
185 | |
186 構築されたレコードから値を取得する際には \verb/RecordName.fieldName/ という名前の関数を適用する(リスト~\ref{src:agda-record-proj} 内2行目) 。 | |
187 なお、レコードにもパターンマッチが利用できる(リスト~\ref{src:agda-record-proj} 内5行目)。 | |
188 また、値を更新する際は \verb/record oldRecord {field = value ; ... }/ という構文を利用する。 | |
189 Point の中の x の値を5増やす関数 \verb/xPlus5/ はリスト~\ref{src:agda-record-proj}の 7,8行目のように書ける。 | |
190 | |
191 \lstinputlisting[label=src:agda-record-proj, caption=Agda におけるレコードの射影、パターンマッチ、値の更新] {src/AgdaRecordProj.agda} | |
192 | |
193 Agda における部分型のように振る舞う機能として Instance Arguments が存在する。 | |
194 これはとあるデータ型が、ある型と名前を持つ関数を持つことを保証する機能であり、Haskell における型クラスや Java におけるインターフェースに相当する。 | |
195 Agda における部分型の制約は、必要な関数を定義した record に相当し、その制約を保証するにはその record を instance として登録することになる。 | |
196 例えば、同じ型と比較することができる、という性質を表すとリスト~\ref{src:agda-type-class}のようになる。 | |
197 具体的にはとある型 A における中置関数 \verb/_==_/ を定義することに相当する。 | |
198 | |
199 \lstinputlisting[label=src:agda-type-class, caption=Agdaにおける部分型制約] {src/AgdaTypeClass.agda} | |
200 | |
201 ある型 T がこの部分型制約を満たすことを示すには、型 T でこのレコードを作成できることを示し、それを instance 構文で登録する。 | |
202 型Nat が Eq の上位型であることを記述するとリスト~\ref{src:agda-instance}のようになる。 | |
203 | |
204 \lstinputlisting[label=src:agda-instance, caption=Agdaにおける部分型関係の構築] {src/AgdaInstance.agda} | |
205 | |
206 これで \verb/Eq/ が要求される関数に対して Nat が適用できるようになる。 | |
207 例えば型 A の要素を持つ List A から要素を探してくる elem を定義する。 | |
208 部分型のインスタンスは \verb/{{}}/ 内部に名前と型名で記述する。 | |
209 なお、名前部分は必須である。 | |
210 仮に変数として受けても利用しない場合は \verb/_/ で捨てると良い。 | |
211 部分型として登録した record は関数本体において \verb/{{variableName}}/ という構文で変数に束縛できる。 | |
212 | |
213 \lstinputlisting[label=src:agda-use-instance, caption=Agdaにおける部分型を使う関数の定義] {src/AgdaElem.agda.replaced} | |
214 | |
215 この \verb/elem/ 関数はリスト~\ref{src:agda-elem-apply} のように利用できる。 | |
216 Nat型の要素を持つリストの内部に4が含まれるか確認している。 | |
217 この \verb/listHas4/ は \verb/true/ に評価される。 | |
218 | |
219 \lstinputlisting[label=src:agda-elem-apply, caption=部分型を持つ関数の適用] {src/AgdaElemApply.agda.replaced} | |
220 | |
221 最後にモジュールについて述べる。 | |
222 モジュールはほとんど名前空間として作用する。 | |
223 なお、依存型の解決はモジュールのインポート時に行なわれる。 | |
224 モジュールをインポートする時は \verb/import/ キーワードを指定する。 | |
225 また、インポートを行なう際に名前を別名に変更することもでき、その際は \verb/as/ キーワードを用いる。 | |
226 モジュールから特定の関数のみをインポートする場合は \verb/using/ キーワードを、関数の名前を変える時は \verb/renaming/キーワードを、特定の関数のみを隠す場合は \verb/hiding/ キーワードを用いる。 | |
227 なお、モジュールに存在する関数をトップレベルで用いる場合は \verb/open/ キーワードを使うことで展開できる。 | |
228 モジュールをインポートする例をリスト~\ref{src:agda-import}に示す。 | |
229 | |
230 \lstinputlisting[label=src:agda-import, caption=Agdaにおけるモジュールのインポート] {src/AgdaImport.agda} | |
231 | |
232 また、モジュールには値を渡すことができる。 | |
233 そのようなモジュールは Parameterized Module と呼ばれ、渡された値はそのモジュール内部で一貫して扱える。 | |
234 例えば要素の型と比較する二項演算子を使って並べ替えをするモジュール\verb/Sort/ を考える。 | |
235 そのモジュールは引数に型Aと二項演算子 \verb/</を取り、ソートする関数を提供する。 | |
236 \verb/Sort/モジュールを \verb/Nat/ と \verb/Bool/ で利用した例がリスト~\ref{src:agda-parameterized-module}である。 | |
237 | |
238 \lstinputlisting[label=src:agda-parameterized-module, caption=Agda における Parameterized Module] {src/AgdaParameterizedModule.agda} | |
57 | 239 |
58 % }}} | 240 % }}} |
59 | 241 |
60 % {{{ Natural Deduction | 242 % {{{ Natural Deduction |
61 \section{Natural Deduction} | 243 \section{Natural Deduction} |
329 \label{tbl:curry_howard_isomorphism} | 511 \label{tbl:curry_howard_isomorphism} |
330 \end{table} | 512 \end{table} |
331 \end{center} | 513 \end{center} |
332 % }}} | 514 % }}} |
333 | 515 |
334 % {{{ 依存型を持つ証明支援系言語 Agda | |
335 | |
336 \section{依存型を持つ証明支援系言語 Agda} | |
337 型システムを用いて証明を行なうことができる言語に Agda~\cite{agda} が存在する。 | |
338 Agda は依存型という強力な型システムを持っている。 | |
339 依存型とは型も第一級オブジェクトとする型であり、型を引数に取る関数や値を取って型を返す関数、型の型などが記述できる。 | |
340 この節では Agda の文法的な紹介を行なう~\cite{Norell:2009:DTP:1481861.1481862}~\cite{agda-documentation}。 | |
341 | |
342 まず Agda のプログラムは全てモジュールの内部に記述されるため、まずはトップレベルにモジュールを定義する必要がある。 | |
343 トップレベルのモジュールはファイル名と同一となる。 | |
344 例えば \verb/AgdaBasics.agda/ のモジュール名定義はリスト~\ref{src:agda-module}のようになる。 | |
345 | |
346 \lstinputlisting[label=src:agda-module, caption=Agdaのモジュールの定義する] {src/AgdaBasics.agda} | |
347 | |
348 また、Agda はインデントに意味を持つ言語であるため、インデントはきちんと揃える必要がある。 | |
349 | |
350 まず Agda におけるデータ型について触れていく。 | |
351 Agda における型指定は $:$ を用いて行なう。 | |
352 例えば、変数xが型Aを持つ、ということを表すには \verb/x : A/ と記述する。 | |
353 | |
354 データ型は Haskell や ML に似て代数的なデータ構造のパターンマッチを扱うことができる | |
355 データ型の定義は \verb/data/ キーワードを用いる。 | |
356 \verb/data/キーワードの後に \verb/where/ 句を書きインデントを深くした後、値にコンストラクタとその型を列挙する。 | |
357 例えば Bool 型を定義するとリスト~\ref{src:agda-bool}のようになる。 | |
358 | |
359 \lstinputlisting[label=src:agda-bool, caption=Agdaにおけるデータ型 Bool の定義] {src/AgdaBool.agda} | |
360 | |
361 Bool はコンストラクタ \verb/true/ か \verb/false/ を持つデータ型である。 | |
362 Bool 自身の型は \verb/Set/ であり、これは Agda が組み込みで持つ「型の型」である。 | |
363 Set は階層構造を持ち、型の型の型を指定するには Set1 と書く。 | |
364 | |
365 関数の定義は Haskell に近い。 | |
366 関数名と型を記述した後に関数の本体を \verb/=/ の後に指定する。 | |
367 関数の型は単純型付き $ \lambda$ 計算と同様に $ \rightarrow $ を用いる。 | |
368 なお、$\rightarrow$に対しては糖衣構文 \verb/->/ も用意されている。 | |
369 引数は変数名で受けることもできるが、具体的なコンストラクタを指定することでそのコンストラクタが渡された時の挙動を定義できる。 | |
370 これはパターンマッチと呼ばれ、コンストラクタで case 文を行なっているようなものである。 | |
371 例えば Bool 型の値を反転する \verb/not/ 関数を書くとリスト~\ref{src:agda-not}のようになる。 | |
372 | |
373 \lstinputlisting[label=src:agda-not, caption=Agdaにおける関数 not の定義] {src/AgdaNot.agda} | |
374 | |
375 関数にはリテラルが存在し、関数名を定義せずともその場で生成することができる。 | |
376 これをラムダ式と呼び、\verb/\arg1 arg2 -> function body/ のように書く。 | |
377 例えば Bool 型の引数 \verb/b/ を取って not を適用する \verb/not-apply/ をラムダ式で書くとリスト~\ref{src:agda-lambda}のようになる。 | |
378 関数 \verb/not-apply/ をラムダ式を使わずに定義すると \verb/not-apply-2/ になるが、この二つの関数は同一の動作をする。 | |
379 | |
380 \lstinputlisting[label=src:agda-lambda, caption=Agda におけるラムダ式] {src/AgdaLambda.agda} | |
381 | |
382 コンストラクタによって処理を分岐する場合はパターンマッチを利用する。 | |
383 関数の変数部分にコンストラクタを指定し、それぞれに対する処理を \verb/=/ で繋いで記述する。 | |
384 パターンマッチは全てのコンストラクタのパターンを含まなくてはならない。 | |
385 なお、コンストラクタをいくつか指定した後に変数で受けると、変数が持ちうる値は指定した以外のコンストラクタとなる。 | |
386 例えばリスト~\ref{src:agda-pattern}の not は x には true しか入ることは無い。 | |
387 なお、マッチした値を変数として利用しない場合は \verb/_/ を用いて捨てることもできる。 | |
388 | |
389 \lstinputlisting[label=src:agda-pattern, caption=Agdaにおけるパターンマッチ] {src/AgdaPattern.agda} | |
390 | |
391 Agda では特定の関数内のみで利用する関数を \verb/where/ 句で記述できる。 | |
392 これは関数内部の冗長な記述を省略するのに活用できる。 | |
393 スコープは \verb/where/句が存在する関数内部のみであるため、名前空間が汚染させることも無い。 | |
394 例えば自然数3つを取ってそれぞれ3倍して加算する関数 \verb/f/ を定義するとき、 \verb/where/ を使うとリスト~\ref{src:agda-where} のように書ける。 | |
395 これは \verb/f'/ と同様の動作をする。 | |
396 \verb/where/ 句は利用したい関数の末尾にインデント付きで \verb/where/ キーワードを記述し、改行の後インデントをして関数内部で利用する関数を定義する。 | |
397 | |
398 \lstinputlisting[label=src:agda-where, caption=Agda における where 句] {src/AgdaWhere.agda} | |
399 | |
400 | |
401 データ型のコンストラクタには自分自身の型を引数に取ることもできる(リスト~\ref{src:agda-nat})。 | |
402 自然数のコンストラクタは2つあり、片方は自然数ゼロ、片方は自然数を取って後続数を返すものである。 | |
403 例えば0 は \verb/zero/ であり、1 は \verb/suc zero/に、3は \verb/suc (suc (suc zero))/ に対応する。 | |
404 | |
405 \lstinputlisting[label=src:agda-nat, caption=Agdaにおける自然数の定義] {src/AgdaNat.agda} | |
406 | |
407 自然数に対する演算は再帰関数として定義できる。 | |
408 例えば自然数どうしの加算は二項演算子\verb/+/としてリスト~\ref{src:agda-plus}のように書ける。 | |
409 | |
410 この二項演算子は正確には中置関数である。 | |
411 前置や後置で定義できる部分を関数名に \verb/_/ として埋め込んでおくことで、関数を呼ぶ時にあたかも前置や後置演算子のように振る舞う。 | |
412 例えば \verb/!_/ 関数を定義すると \verb/! true/ のように利用でき、\verb/_~/ 関数を定義すると \verb/false ~/ のように利用できる。 | |
413 | |
414 また、Agda は再帰関数が停止するかを判定できる。 | |
415 この加算の二項演算子は左側がゼロに対しては明らかに停止する。 | |
416 左側が1以上の時の再帰時には \verb/suc n/ から \verb/n/へと減っているため、再帰で繰り返し減らすことでいつかは停止する。 | |
417 もし \verb/suc n/ のまま自分自身へと再帰した場合、Agda は警告を出す。 | |
418 | |
419 \lstinputlisting[label=src:agda-plus, caption=Agda における自然数の加算の定義] {src/AgdaPlus.agda} | |
420 | |
421 次に依存型について見ていく。 | |
422 依存型で最も基本的なものは関数型である。 | |
423 依存型を利用した関数は引数の型に依存して返す型を決定できる。 | |
424 | |
425 Agda で \verb/(x : A) -> B/ と書くと関数は型 A を持つx を受け取り、Bを返す。 | |
426 ここで B の中で x を扱っても良い。 | |
427 例えば任意の型に対する恒等関数はリスト~\ref{src:agda-id}のように書ける。 | |
428 | |
429 \lstinputlisting[label=src:agda-id, caption=依存型を持つ関数の定義] {src/AgdaId.agda} | |
430 | |
431 この恒等関数 \verb/identitiy/ は任意の型に適用可能である。 | |
432 実際に関数 \verb/identitiy/ を Nat へ適用した例が \verb/identitiy-zero/ である。 | |
433 | |
434 多相の恒等関数では型を明示的に指定せずとも \verb/zero/ に適用した場合の型は自明に \verb/Nat -> Nat/である。 | |
435 Agda はこのような推論をサポートしており、推論可能な引数は省略できる。 | |
436 推論によって解決される引数を暗黙的な引数(implicit arguments) と言い、記号 \verb/{}/ でくくる。 | |
437 | |
438 例えば、\verb/identitiy/ の対象とする型\verb/A/を暗黙的な引数として省略するとリスト~\ref{src:agda-implicit-id}のようになる。 | |
439 この恒等関数を利用する際は特定の型に属する値を渡すだけでその型が自動的に推論される。 | |
440 よって関数を利用する際は \verb/id-zero/ のように型を省略して良い。 | |
441 なお、関数の本体で暗黙的な引数を利用したい場合は \verb/{variableName}/ で束縛することもできる(\verb/id'/ 関数)。 | |
442 適用する場合も \verb/{}/でくくり、\verb/id-true/のように使用する。 | |
443 | |
444 \lstinputlisting[label=src:agda-implicit-id, caption=Agdaにおける暗黙的な引数を持つ関数] {src/AgdaImplicitId.agda} | |
445 | |
446 Agda には C における構造体に相当するレコード型も存在する。 | |
447 定義を行なう際は \verb/record/キーワードの後にレコード名、型、\verb/where/ の後に \verb/field/ キーワードを入れた後、フィールド名と型名を列挙する。 | |
448 例えば x と y の二つの自然数からなるレコード \verb/Point/ を定義するとリスト~\ref{src:agda-record}のようになる。 | |
449 レコードを構築する際は \verb/record/ キーワードの後の \verb/{}/ の内部に \verb/fieldName = value/ の形で値を列挙していく。 | |
450 複数の値を列挙する際は \verb/;/ で区切る。 | |
451 | |
452 \lstinputlisting[label=src:agda-record, caption=Agdaにおけるレコード型の定義] {src/AgdaRecord.agda} | |
453 | |
454 構築されたレコードから値を取得する際には \verb/RecordName.fieldName/ という名前の関数を適用する(リスト~\ref{src:agda-record-proj} 内2行目) 。 | |
455 なお、レコードにもパターンマッチが利用できる(リスト~\ref{src:agda-record-proj} 内5行目)。 | |
456 また、値を更新する際は \verb/record oldRecord {field = value ; ... }/ という構文を利用する。 | |
457 Point の中の x の値を5増やす関数 \verb/xPlus5/ はリスト~\ref{src:agda-record-proj}の 7,8行目のように書ける。 | |
458 | |
459 \lstinputlisting[label=src:agda-record-proj, caption=Agda におけるレコードの射影、パターンマッチ、値の更新] {src/AgdaRecordProj.agda} | |
460 | |
461 Agda における部分型のように振る舞う機能として Instance Arguments が存在する。 | |
462 これはとあるデータ型が、ある型と名前を持つ関数を持つことを保証する機能であり、Haskell における型クラスや Java におけるインターフェースに相当する。 | |
463 Agda における部分型の制約は、必要な関数を定義した record に相当し、その制約を保証するにはその record を instance として登録することになる。 | |
464 例えば、同じ型と比較することができる、という性質を表すとリスト~\ref{src:agda-type-class}のようになる。 | |
465 具体的にはとある型 A における中置関数 \verb/_==_/ を定義することに相当する。 | |
466 | |
467 \lstinputlisting[label=src:agda-type-class, caption=Agdaにおける部分型制約] {src/AgdaTypeClass.agda} | |
468 | |
469 ある型 T がこの部分型制約を満たすことを示すには、型 T でこのレコードを作成できることを示し、それを instance 構文で登録する。 | |
470 型Nat が Eq の上位型であることを記述するとリスト~\ref{src:agda-instance}のようになる。 | |
471 | |
472 \lstinputlisting[label=src:agda-instance, caption=Agdaにおける部分型関係の構築] {src/AgdaInstance.agda} | |
473 | |
474 これで \verb/Eq/ が要求される関数に対して Nat が適用できるようになる。 | |
475 例えば型 A の要素を持つ List A から要素を探してくる elem を定義する。 | |
476 部分型のインスタンスは \verb/{{}}/ 内部に名前と型名で記述する。 | |
477 なお、名前部分は必須である。 | |
478 仮に変数として受けても利用しない場合は \verb/_/ で捨てると良い。 | |
479 部分型として登録した record は関数本体において \verb/{{variableName}}/ という構文で変数に束縛できる。 | |
480 | |
481 \lstinputlisting[label=src:agda-use-instance, caption=Agdaにおける部分型を使う関数の定義] {src/AgdaElem.agda.replaced} | |
482 | |
483 この \verb/elem/ 関数はリスト~\ref{src:agda-elem-apply} のように利用できる。 | |
484 Nat型の要素を持つリストの内部に4が含まれるか確認している。 | |
485 この \verb/listHas4/ は \verb/true/ に評価される。 | |
486 なお、 \verb/--/ の後はコメントである。 | |
487 | |
488 \lstinputlisting[label=src:agda-elem-apply, caption=部分型を持つ関数の適用] {src/AgdaElemApply.agda.replaced} | |
489 | |
490 最後にモジュールについて述べる。 | |
491 モジュールはほとんど名前空間として作用する。 | |
492 なお、依存型の解決はモジュールのインポート時に行なわれる。 | |
493 モジュールをインポートする時は \verb/import/ キーワードを指定する。 | |
494 また、インポートを行なう際に名前を別名に変更することもでき、その際は \verb/as/ キーワードを用いる。 | |
495 モジュールから特定の関数のみをインポートする場合は \verb/using/ キーワードを、関数の名前を変える時は \verb/renaming/キーワードを、特定の関数のみを隠す場合は \verb/hiding/ キーワードを用いる。 | |
496 なお、モジュールに存在する関数をトップレベルで用いる場合は \verb/open/ キーワードを使うことで展開できる。 | |
497 モジュールをインポートする例をリスト~\ref{src:agda-import}に示す。 | |
498 | |
499 \lstinputlisting[label=src:agda-import, caption=Agdaにおけるモジュールのインポート] {src/AgdaImport.agda} | |
500 | |
501 また、モジュールには値を渡すことができる。 | |
502 そのようなモジュールは Parameterized Module と呼ばれ、渡された値はそのモジュール内部で一貫して扱える。 | |
503 例えば要素の型と比較する二項演算子を使って並べ替えをするモジュール\verb/Sort/ を考える。 | |
504 そのモジュールは引数に型Aと二項演算子 \verb/</を取り、ソートする関数を提供する。 | |
505 \verb/Sort/モジュールを \verb/Nat/ と \verb/Bool/ で利用した例がリスト~\ref{src:agda-parameterized-module}である。 | |
506 | |
507 \lstinputlisting[label=src:agda-parameterized-module, caption=Agda における Parameterized Module] {src/AgdaParameterizedModule.agda} | |
508 | |
509 % }}} | |
510 | |
511 % {{{ Reasoning | 516 % {{{ Reasoning |
512 | 517 |
513 \section{Reasoning} | 518 \section{Reasoning} |
514 次に Agda における証明を記述していく。 | 519 次に Agda における証明を記述していく。 |
515 例題として、自然数の加法の可換法則を示す。 | 520 例題として、自然数の加法の可換法則を示す。 |