Mercurial > hg > Papers > 2018 > nozomi-master
comparison paper/agda.tex @ 79:4985359bd08b
Update agda description
author | atton <atton@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 08 Feb 2017 15:52:44 +0900 |
parents | 897fda8e39c5 |
children | 73da47f32888 |
comparison
equal
deleted
inserted
replaced
78:897fda8e39c5 | 79:4985359bd08b |
---|---|
21 型システムで行なえることには以下のようなものが存在する。 | 21 型システムで行なえることには以下のようなものが存在する。 |
22 | 22 |
23 \begin{itemize} | 23 \begin{itemize} |
24 \item エラーの検出 | 24 \item エラーの検出 |
25 | 25 |
26 文字列演算を行なう関数に整数を渡してしまったり、データの単位を間違えてしまったり、複雑な場合分けで境界条件を見落すなど、プログラマの不注意が型の不整合となって早期に指摘できる。 | 26 文字列演算を行なう関数に整数を渡してしまったり、複雑な場合分けで境界条件を見落すなど、プログラマの不注意が型の不整合として表れる。 |
27 この指摘できる詳細さは、型システムの表現力とプログラムの内容に依存する。 | |
28 多用なデータ構造を扱うプログラム(コンパイラのような記号処理アプリケーションなど)は数値計算のような数種類の単純な型しか使わないプログラムよりも型検査器から受けられる恩恵が大きい。 | |
29 他にも、ある種のプログラムにとっては型は保守のためのツールともなる。 | |
30 複雑なデータ構造を変更する時、その構造に関連するソースコードを型検査器は明らかにしてくれる。 | |
31 | 27 |
32 \item 抽象化 | 28 \item 抽象化 |
33 | 29 |
34 型は大規模プログラムの抽象化の単位にもなる。 | 30 型は大規模プログラムの抽象化の単位にもなる。 |
35 例えば特定のデータ構造に対する処理をモジュール化し、パッケージングすることができる。 | 31 例えば特定のデータ構造に対する処理をモジュール化し、パッケージングすることができる。 |
36 モジュール化されたデータ構造は厳格に定義されたインターフェースを経由して呼び出すことになる。 | |
37 このインターフェースは利用する側に取っては呼び出しの規約となり、実装する側にとってはモジュールの要約となる。 | |
38 | 32 |
39 \item ドキュメント化 | 33 \item ドキュメント化 |
40 | 34 |
41 型はプログラムを理解する際にも有用である。 | 35 関数やモジュールの型を確認することにより、プログラムの理解の助けになる。 |
42 関数やモジュールの型を確認することにより、どのデータを対象としているのかといった情報が手に入る。 | 36 また、型はコンパイラが実行されるたびに検査されるため、常に最新の正しい情報を提供する。 |
43 また、型はコンパイラが実行されるために検査されるため、コメントに埋め込まれた情報と異なり常に正しい情報を提供する。 | |
44 | 37 |
45 \item 言語の安全性 | 38 \item 言語の安全性 |
46 | 39 |
47 安全性のの定義は言語によって異なるが、型はデータの抽象化によってある種の安全性を確保できる。 | 40 例えばポインタを直接扱わないようメモリアクセスを抽象化し、データを破壊する可能性をプログラマに提供しないようにできる。 |
48 例えば、プログラマは配列をソートする関数があった場合、与えられた配列のみがソートされ、他のデータには影響が無いことを期待するだろう。 | |
49 しかし、低水準言語ではメモリを直接扱えるため、予想された処理の範囲を越えてデータを破壊する可能性がある。 | |
50 より安全な言語ではメモリアクセスが抽象化し、データを破壊する可能性をプログラマに提供しないという選択肢がある。 | |
51 | 41 |
52 \item 効率性 | 42 \item 効率性 |
53 | 43 |
54 そもそも、科学計算機における最初の型システムは Fortran~\ref{Backus:1978:HFI:960118.808380} などにおける式の区別であった。 | 44 そもそも、科学計算機における最初の型システムは Fortran~\ref{Backus:1978:HFI:960118.808380} などにおける整数と実数の算術式の区別だった。 |
55 整数の算術式と実数の算術式を区別し、数値計算の効率化を測るために導入されたのである。 | 45 型の導入により、ソースからコンパイラがより最適化されたコードを生成できる。 |
56 型の導入により、コンパイラはプリミティブな演算とは異なる表現を用い、実行コードを生成する時に適切な機械語表現を行なえるようになった。 | |
57 昨今の高性能コンパイラでは最適化とコード生成のフェーズにおいて型検査器が収集する情報を多く利用している。 | |
58 | 46 |
59 \end{itemize} | 47 \end{itemize} |
60 | 48 |
61 型システムの定義には多くの定義が存在する。 | 49 型システムには多くの定義が存在する。 |
62 型の表現能力には単純型や総称型、部分型などが存在し、動的型付けや静的型付けなど、言語によってどの型システムを採用するかは言語の設計に依存する。 | 50 型の表現能力には単純型や総称型、部分型などが存在する。 |
51 型付けにも動的型付けや静的型付けが存在し、どの型システムを採用するかは言語の設計に依存する。 | |
63 例えば C言語では数値と文字を二項演算子 \verb/+/ で加算できるが、Haskell では加算することができない。 | 52 例えば C言語では数値と文字を二項演算子 \verb/+/ で加算できるが、Haskell では加算することができない。 |
64 これは Haskell が C言語よりも厳密な型システムを採用しているからである。 | 53 これは Haskell が C言語よりも厳密な型システムを採用しているからである。 |
65 具体的には Haskell は暗黙的な型変換を許さず、 C 言語は言語仕様として暗黙の型変換を持っている。 | 54 具体的には Haskell は暗黙的な型変換を許さず、 C 言語は言語仕様として暗黙の型変換を持っている。 |
66 | 55 |
67 型システムを定義することはプログラミング言語がどのような特徴を持つか決めることにも繋がる。 | 56 型システムを定義することはプログラミング言語がどのような特徴を持つかを決めることにも繋がる。 |
68 | 57 |
69 % }}} | 58 % }}} |
70 | 59 |
71 % {{{ Natural Deduction | 60 % {{{ Natural Deduction |
72 \section{Natural Deduction} | 61 \section{Natural Deduction} |
381 これはパターンマッチと呼ばれ、コンストラクタで case 文を行なっているようなものである。 | 370 これはパターンマッチと呼ばれ、コンストラクタで case 文を行なっているようなものである。 |
382 例えば Bool 型の値を反転する \verb/not/ 関数を書くとリスト~\ref{src:agda-not}のようになる。 | 371 例えば Bool 型の値を反転する \verb/not/ 関数を書くとリスト~\ref{src:agda-not}のようになる。 |
383 | 372 |
384 \lstinputlisting[label=src:agda-not, caption=Agdaにおける関数 not の定義] {src/AgdaNot.agda} | 373 \lstinputlisting[label=src:agda-not, caption=Agdaにおける関数 not の定義] {src/AgdaNot.agda} |
385 | 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/=/ で繋いで記述する。 | |
386 パターンマッチは全てのコンストラクタのパターンを含まなくてはならない。 | 384 パターンマッチは全てのコンストラクタのパターンを含まなくてはならない。 |
387 パターンマッチは上からマッチされていくため、優先順位が存在する。 | 385 なお、コンストラクタをいくつか指定した後に変数で受けると、変数が持ちうる値は指定した以外のコンストラクタとなる。 |
388 なお、コンストラクタをいくつか指定した後に変数で受けると、変数が持ちうる値は指定したコンストラクタ以外となる。 | 386 例えばリスト~\ref{src:agda-pattern}の not は x には true しか入ることは無い。 |
389 例えばリスト~\ref{src:agda-pattern}のnot は x には true しか入ることは無い。 | 387 なお、マッチした値を変数として利用しない場合は \verb/_/ を用いて捨てることもできる。 |
390 | 388 |
391 \lstinputlisting[label=src:agda-pattern, caption=Agdaにおけるパターンマッチ] {src/AgdaPattern.agda} | 389 \lstinputlisting[label=src:agda-pattern, caption=Agdaにおけるパターンマッチ] {src/AgdaPattern.agda} |
392 | 390 |
393 なお、マッチした値を変数として利用しない場合は \verb/_/ を用いて捨てることもできる。 | 391 Agda では特定の関数内のみで利用する関数を \verb/where/ 句で記述できる。 |
394 | 392 これは関数内部の冗長な記述を省略するのに活用できる。 |
395 単純型で利用した自然数もデータ型として定義できる(リスト~\ref{src:agda-nat})。 | 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})。 | |
396 自然数のコンストラクタは2つあり、片方は自然数ゼロ、片方は自然数を取って後続数を返すものである。 | 402 自然数のコンストラクタは2つあり、片方は自然数ゼロ、片方は自然数を取って後続数を返すものである。 |
397 例えば0 は \verb/zero/ であり、1 は \verb/suc zero/に、3は \verb/suc (suc (suc zero))/ に対応する。 | 403 例えば0 は \verb/zero/ であり、1 は \verb/suc zero/に、3は \verb/suc (suc (suc zero))/ に対応する。 |
398 | 404 |
399 \lstinputlisting[label=src:agda-nat, caption=Agdaにおける自然数の定義] {src/AgdaNat.agda} | 405 \lstinputlisting[label=src:agda-nat, caption=Agdaにおける自然数の定義] {src/AgdaNat.agda} |
400 | 406 |
401 自然数に対する演算は再帰関数として定義できる。 | 407 自然数に対する演算は再帰関数として定義できる。 |
402 例えば自然数どうしの加算は二項演算子\verb/+/としてリスト~\ref{src:agda-plus}のように書ける。 | 408 例えば自然数どうしの加算は二項演算子\verb/+/としてリスト~\ref{src:agda-plus}のように書ける。 |
403 | 409 |
404 この二項演算子は正確には中置関数である。 | 410 この二項演算子は正確には中置関数である。 |
405 前置や後置で定義できる部分を関数名に \verb/_/ として埋め込んでおくことで、関数を呼ぶ時にあたかも前置演算子のように振る舞う。 | 411 前置や後置で定義できる部分を関数名に \verb/_/ として埋め込んでおくことで、関数を呼ぶ時にあたかも前置や後置演算子のように振る舞う。 |
406 また、Agda は関数が停止するかを判定できる。 | 412 例えば \verb/!_/ 関数を定義すると \verb/! true/ のように利用でき、\verb/_~/ 関数を定義すると \verb/false ~/ のように利用できる。 |
413 | |
414 また、Agda は再帰関数が停止するかを判定できる。 | |
407 この加算の二項演算子は左側がゼロに対しては明らかに停止する。 | 415 この加算の二項演算子は左側がゼロに対しては明らかに停止する。 |
408 左側が1以上の時の再帰時には \verb/suc n/ から \verb/n/へと減っているため、再帰で繰り返し減らすことでいつかは停止する。 | 416 左側が1以上の時の再帰時には \verb/suc n/ から \verb/n/へと減っているため、再帰で繰り返し減らすことでいつかは停止する。 |
417 もし \verb/suc n/ のまま自分自身へと再帰した場合、Agda は警告を出す。 | |
409 | 418 |
410 \lstinputlisting[label=src:agda-plus, caption=Agda における自然数の加算の定義] {src/AgdaPlus.agda} | 419 \lstinputlisting[label=src:agda-plus, caption=Agda における自然数の加算の定義] {src/AgdaPlus.agda} |
411 | 420 |
412 次に依存型について見ていく。 | 421 次に依存型について見ていく。 |
413 依存型で最も基本的なものは関数型である。 | 422 依存型で最も基本的なものは関数型である。 |
432 なお、関数の本体で暗黙的な引数を利用したい場合は \verb/{variableName}/ で束縛することもできる(\verb/id'/ 関数)。 | 441 なお、関数の本体で暗黙的な引数を利用したい場合は \verb/{variableName}/ で束縛することもできる(\verb/id'/ 関数)。 |
433 適用する場合も \verb/{}/でくくり、\verb/id-true/のように使用する。 | 442 適用する場合も \verb/{}/でくくり、\verb/id-true/のように使用する。 |
434 | 443 |
435 \lstinputlisting[label=src:agda-implicit-id, caption=Agdaにおける暗黙的な引数を持つ関数] {src/AgdaImplicitId.agda} | 444 \lstinputlisting[label=src:agda-implicit-id, caption=Agdaにおける暗黙的な引数を持つ関数] {src/AgdaImplicitId.agda} |
436 | 445 |
437 Agda にはレコード型も存在する。 | 446 Agda には C における構造体に相当するレコード型も存在する。 |
438 定義を行なう際は \verb/record/キーワードの後にレコード名、型、\verb/where/ の後に \verb/field/ キーワードを入れた後、フィールド名と型名を列挙する。 | 447 定義を行なう際は \verb/record/キーワードの後にレコード名、型、\verb/where/ の後に \verb/field/ キーワードを入れた後、フィールド名と型名を列挙する。 |
439 例えば x と y の二つの自然数からなるレコード \verb/Point/ を定義するとリスト~\ref{src:agda-record}のようになる。 | 448 例えば x と y の二つの自然数からなるレコード \verb/Point/ を定義するとリスト~\ref{src:agda-record}のようになる。 |
440 レコードを構築する際は \verb/record/ キーワードの後の \verb/{}/ の内部に \verb/fieldName = value/ の形で値を列挙していく。 | 449 レコードを構築する際は \verb/record/ キーワードの後の \verb/{}/ の内部に \verb/fieldName = value/ の形で値を列挙していく。 |
441 複数の値を列挙する際は \verb/;/ で区切る。 | 450 複数の値を列挙する際は \verb/;/ で区切る。 |
442 | 451 |
495 そのモジュールは引数に型Aと二項演算子 \verb/</を取り、ソートする関数を提供する。 | 504 そのモジュールは引数に型Aと二項演算子 \verb/</を取り、ソートする関数を提供する。 |
496 \verb/Sort/モジュールを \verb/Nat/ と \verb/Bool/ で利用した例がリスト~\ref{src:agda-parameterized-module}である。 | 505 \verb/Sort/モジュールを \verb/Nat/ と \verb/Bool/ で利用した例がリスト~\ref{src:agda-parameterized-module}である。 |
497 | 506 |
498 \lstinputlisting[label=src:agda-parameterized-module, caption=Agda における Parameterized Module] {src/AgdaParameterizedModule.agda} | 507 \lstinputlisting[label=src:agda-parameterized-module, caption=Agda における Parameterized Module] {src/AgdaParameterizedModule.agda} |
499 | 508 |
500 % TODO: where 句の説明 | |
501 | |
502 % }}} | 509 % }}} |
503 | 510 |
504 % {{{ Reasoning | 511 % {{{ Reasoning |
505 | 512 |
506 \section{Reasoning} | 513 \section{Reasoning} |