--- title: 6章・7章 tags: presentation slideOptions: theme: white slideNumber: 'c/t' center: false transition: 'none' keyboard: true width: '93%' height: '100%' --- <style> /* basic design */ .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6, .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p { font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic'; text-align: left; line-height: 1.6; letter-spacing: normal; text-shadow: none; word-wrap: break-word; color: #444; } .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {font-weight: bold;} .reveal h1, .reveal h2, .reveal h3 {color: #00a474;} .reveal th {background: #DDD;} .reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;} .reveal blockquote {width: 90%; padding: 0.5vw 3.0vw;} .reveal table {margin: 1.0vw auto;} .reveal code {line-height: 1.2;} .reveal p, .reveal li {padding: 0vw; margin: 0vw;} .reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #e4ffe5; border-radius: 1.5vw;} /* table design */ .reveal table {background: #f5f5f5;} .reveal th {background: #444; color: #fff;} .reveal td {position: relative; transition: all 300ms;} .reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #aaa;} .reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #fff;} /* blockquote design */ .reveal blockquote { width: 90%; padding: 0.5vw 0 0.5vw 6.0vw; font-style: italic; background: #ddffff; } .reveal blockquote:before{ position: absolute; top: 0.1vw; left: 1vw; content: "\f10d"; font-family: FontAwesome; color: #00a474; font-size: 3.0vw; } /* font size */ .reveal h1 {font-size: 5.0vw;} .reveal h2 {font-size: 4.0vw;} .reveal h3 {font-size: 2.8vw;} .reveal h4 {font-size: 2.6vw;} .reveal h5 {font-size: 2.4vw;} .reveal h6 {font-size: 2.2vw;} .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.2vw;} .reveal code {font-size: 1.6vw;} /* new color */ .red {color: #EE6557;} .blue {color: #16A6B6;} /* split slide */ #right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;} #left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;} </style> <style> /* backgroud design */ .reveal { background-color:/*背景色*/ #f8f8ff; } .reveal h1 {padding: 3.0vw 0vw;} @media screen and (max-width: 1024px) { .reveal h2 {margin: -2.0vw 0 0 0; padding: 0.0vw 0vw 3.0vw 2.0vw; } } @media screen and (min-width: 1025px) and (max-width: 1920px) { .reveal h2 {margin: -1.5vw 0 0 0; padding: 0.0vw 0vw 3.0vw 2.0vw; } } @media screen and (min-width: 1921px) and (max-width: 100000px) { .reveal h2 {margin: -1.0vw 0 0 0; padding: 0.0vw 0vw 3.0vw 2.0vw; } } </style> <style> /* specific design */ .reveal h2 { padding: 0 1.5vw; margin: 0.0vw 0 2.0vw -2.0vw; border-left: solid 1.2vw #00a474; border-bottom: solid 0.8vw #9e9e9e; } </style> # 6章 さまざまなエラー ## 6.1 構文エラー #### ・ 構文エラーとは 構文がおかしい時に起きるエラー 「syntax error」というメッセージが表示される #### ・例 例1 let文で変数を宣言しようとしているのに「=」を書き忘れた場合 ```ocaml= let x 3;; Error: Syntax error ``` 例2 if文でthen部分を書き忘れてしまった場合 ```ocaml= if 2 > 3 then else 3;; Error: Syntax error ``` 例3 括弧の対応が不適切な場合 ```ocaml= 3 + 4) * 2 ;; Error: Syntax error ``` 例4 閉じ括弧を忘れている場合 ```ocaml= (3 + 4 ;; Error: Syntax error: ')' expected ``` #### ・Illegal character 構文エラーと似たエラーで、そもそもプログラムには使えない文字を使ってしまった場合 「Illegal character」と表示される 例 漢字を文字列の中ではなく、プログラム中に直接書いてしまった場合 ```ocaml= 新^横浜 ;; Error: Illegal character ``` ## 6.2 未定義の変数 #### ・Unbound value 未定義の変数を使おうとすると、「Unbound value」というエラーが発生する <b>例</b> 例1 aを定義し忘れた場合 ```ocaml= 2 + a * 4;; Error: Unbound value a ``` 例2 定義する際にletではなくlatと書いてしまった場合(誤字) ```ocaml= lat x = 3 ;; Error: Unbound value lat ```  例2の場合、インタプリタはこれがlet文であることがわからず、latという未定義の変数が使われていると解釈して「Unbound value」のエラーを出してしまう #### ・Unbound constructor Unbound valueと似たエラーとして<b>Unbound constructor</b>がある 変数は小文字で始まらなくてはならないが、間違えて大文字で始めるとこのエラーになる <b>例</b> ```ocaml= A ;; Error: Unbound constructor A ``` ## 6.3 型エラー #### ・型エラーとは 型が合っていない場合に起こるエラー #### ・例 例1 整数の加算をしているのに実数を渡してしまった場合 ```ocaml= 3 + 2.5 ;; Error: This expression has type float but an expression was expected of type int ``` OCamlのインタプリタは、エラーが起きるとその場所をアンダーラインで示してくれる (3+<u>2.5</u> ; ;) 例2 実数の加算をしようと思っているところに整数の加算を使ってしまった場合 ```ocaml= 1.0 + 2.0 ;; Error: This expression has type float but an expression was expected of type int ``` アンダーラインで示されたのは、+ではなく1.0 ( <u>1.0</u> + 2.0 ; ; ) このように、インタプリタのエラーメッセージは常に我々の意図を理解しているわけではない #### ・型エラーの特殊な場合 例1 sinがひとつしか引数を受け取らないのに間違ってふたつ渡してしまった場合 ```ocaml= sin 3.14 0. ;; Error: This function has type float -> float It is applied to too many arguments; maybe you forgot a `;'. ``` エラーメッセージに出てくる<b>argument</b>というのは引数のこと エラーメッセージの最後の<b>maybe</b>以下は「どこかに;を書き忘れているのかも知れません」 という意味 例2 if文を書くときにelseというキーワードを書き忘れてしまった場合 ```ocaml= if 2 > 3 then sin 3.14 cos 0.0 ;; Error: This function has type float -> float It is applied to too many arguments; maybe you forgot a `;'. ``` このように書くと、OCamlインタプリタはsinに3.14とcosと0.0の3つの引数が渡されたと解釈してしまう ## 6.4 実行時のエラー #### ・実行時のエラーとは プログラムの構文は問題ないけれど、実際にそのプログラムを実行していたら途中でどうしてもそれ以上、実行を継続できなくなった場合に起きる 例 0で割ってしまった場合 ```ocaml= 3 / 0 ;; Exception: Division_by_zero. ``` この場合、OCamlインタプリタは<b>Division_by_zero</b>という例外を発生してプログラムの実行を終了する ## 6.5 論理的なエラー #### ・論理的なエラーとは エラーメッセージがでないエラー そもそもの考え方が間違っている場合 例 半径rの円の面積を求めたいのに、間違って円周の長さを求めてしまっている場合 ```ocaml= let menseki r = 2.*.pi*.r ;; val menseki : float -> float = <fun> menseki 10. ;; - : float = 62.8000000000000043 ``` 例で求まるのは円周の長さ、面積は求まらない このような間違いは決してOCamlインタプリタは見つけてくれない OCamlのエラーメッセージや型システムは間違いを減らすのに役に立つが、すべてのエラーがなくなるわけではない # 7章 組とパターンマッチ ## 7.1 組の構文 #### ・組とは 組というのは、いくつかのデータを並べて一つのデータにしたもの <b>例</b>:ふたつの実数を並べて作った2次元平面上の点 2次元平面上の点は、ふたつの実数xとyを使って(x、y)と表現される。内部でxとyというふたつの実数を使っているが、全体としてはひとつの点を表している。 #### ・組の表現方法 組は要素の値をコンマで区切って表現する 例1 ```ocaml= (3.14,2.71);; - : float * float = (3.14, 2.71) ``` 組の型は要素の型を*でつないだものになる ( 3.14 , 2.71 )は float型 なので、全体の型は <b>float型*float型</b> になる 組は違う型の要素を並べても構わない 例2 ```ocaml= (3,true);; - : int * bool = (3, true) ``` int型 と bool型 を組にしたもの 3つ以上の要素を並べても構わない 例3 ```ocaml= (3,"a",3.14);; - : int * string * float = (3, "a", 3.14) ``` <b>3</b>(int型)と <b>a</b>(string型) と<b>3.14</b>(float型)の3つを組にしたもの 組の組も作ることが出来る 例3 ```ocaml= ((3,"a"),3.14);; - : (int * string) * float = ((3, "a"), 3.14) ``` 例3は「整数と文字列の組」と「実数」というふたつの要素の組 括弧は省略可能 例4 ```ocaml= 3.14,2.71 ;; - : float * float = (3.14, 2.71) ``` コンマさえあれば括弧が省略可能だが、読みにくくなるだけ #### ・問題7.1 国語、数学、英語、理科、社会の5つの点数を与えられたら、その合計点と平均点を組にして返す関数 <b>goukei_to_heikin</b> を定義せよ。 ```ocaml= let goukei_to_heikin kokugo suugaku eigo rika shakai=(kokugo+suugaku+eigo+rika+shakai,(kokugo+suugaku+eigo+rika+shakai)/5);; val goukei_to_heikin : int -> int -> int -> int -> int -> int * int = <fun> goukei_to_heikin 87 58 95 67 77;; - : int * int = (384, 76) ``` ## 7.2 パターンマッチ #### ・パターンマッチとは 組に限らず複数のデータからできているデータの中身を取り出すにはパターンマッチ(パターンの照合)を使う #### ・パターンマッチの構文 match <span style="background:linear-gradient(transparent 70%,#ff7f7f 0%);"> 式1</span> with <span style="background:linear-gradient(transparent 70%,#ff7f 0%);">パターン</span>-> <span style="background:linear-gradient(transparent 70%,#7fbfff 0%);">式2</span> ① <span style="background:linear-gradient(transparent 70%,#ff7f7f 0%);"> 式1</span>を実行 ② ①の結果を<span style="background:linear-gradient(transparent 70%,#ff7f 0%);">パターン</span>と照合 (パターンとはデータの形を指定するもの) ③ ②の照合結果を使って最後の<span style="background:linear-gradient(transparent 70%,#7fbfff 0%);">式2</span>を実行 #### ・例 例1 組を作った直後にパターンマッチで要素を取り出す ```ocaml= match (3,5) with (a,b)->a+b;; - : int = 8 ```  <span style="background:linear-gradient(transparent 70%,#ff7f 0%);">( a , b )</span>というのがふたつの組を表すパターン aとbは<b>パターン変数</b>と呼ばれ、構造データの要素を取り出すのに使われる <span style="background:linear-gradient(transparent 70%,#ff7f7f 0%);">( 3 , 5 )</span>という組からパターンマッチを使って要素を取り出す 1. <span style="background:linear-gradient(transparent 70%,#ff7f7f 0%);">( 3 , 5 )</span>という組が<span style="background:linear-gradient(transparent 70%,#ff7f 0%);">( a , b )</span>と照合 1. パターン変数aの値が3に、bの値が5になる 1. <span style="background:linear-gradient(transparent 70%,#7fbfff 0%);">( a + b )</span>が実行される 例2 別の場所で作られた組を受け取りその要素を取り出して加える関数 ```ocaml= let add pair = match pair with ( a , b ) -> a + b ;; val add : int * int -> int = <fun> ``` ・関数`add`は引数として、pairを受け取る (このとき渡されるpairは必ずふたつの整数の組でなければならない) ・ふたつの整数の組を引数pairに受け取る ・関数`add`はその中のふたつの要素を加えた結果を返す 関数`add`を使って組( 3, 5 )の要素を加えるなら以下のようになる 例3 ```ocaml= add (3,5);; - : int = 8 ``` また、Ocamlの関数定義の構文は、引数の部分にパターンを書くことができる 例2の定義は以下のよに書くこともできる 例4 ```ocaml= let add (a,b) = a + b ;; val add : int * int -> int = <fun> ``` <span style="background:linear-gradient(transparent 70%,#ff7f 0%);">(a,b)</span>という整数の組を受け取ってきて、その和を返す関数`add`を定義したことになる <span style="background:linear-gradient(transparent 70%,#ff7f 0%);">(a,b)</span>というパターンが<b>引数</b>の役割もしている 例2と例4の違いは、 関数本体で<u>pairという変数を使うことができるかどうか</u>のみ つまり、 例2はpairという変数で組全体を指すが 例4ではpairが使えない、プログラムは短くできる 例2と例4どちらが良いかは実際にプログラム本体を書き始めてみないとわからない (本書では例4は使わない) 例5 引数pairとして、ふたつの整数の組、かつふたつの値が等しいもののみを受け取る関数の定義 ```ocaml= let f pair = match pair with (a,a)->a+a;; Error: Variable a is bound several times in this matching ``` match文や関数の引数のパターンを書く際には、 <u>パターン変数はお互いに異なっていなくてはならない </u>という制限があるので 例5のように書くことはできない ふたつの変数を加えるだけなら、次のような関数を作ることができる 例6 ```ocaml= let add2 a b = a + b ;; val add2 : int -> int -> int = <fun> ``` この関数は、a と b を一度に受け取るのではなく、別々に受け取りそれらの和を返す ```ocaml= add2 3 5 ;; - : int = 8 ``` <b>組として受け取る場合と別々に受け取る場合、どちらが良いか?</b>  ふたつの受け取ってくる値によって受け取り方を変えると良い ・意味的にひとつのもの(座標平面上のx座標とy座標など)⇒組にしてひとつのものと扱う ・関係のないふたつの値(別々に受け取りその和を返すときなど)⇒ひとつの組にするのは避ける #### ・問題7.2 名前と成績の組を受け取ったら「〇〇さんの評価は△です」という文字列を返す関数 <b>seiseki</b> を定義せよ ```ocaml= let seiseki pair = match pair with (name,seiseki1)->name ^"さんの成績は"^seiseki1^"です";; val seiseki : string * string -> string = <fun> seiseki ("佐藤","可");; - : string = "佐藤さんの成績は可です" ``` ## 7.3 構造データに対するデザインレシピ #### ・デザインレシピ 構造をもつデータを扱うをときには、今までのデザインレシピの4項目に<b>テンプレート</b>を追加 全体 <ul> <li>目的</li> <li>例</li> <li>テンプレート</li> <li>本体</li> <li>テスト</li> </ul> #### ・テンプレート テンプレートとは、入力データの型から必然的に決まってくるプログラムの形、「ひな形」のこと テンプレートでは、中身を取り出す match文 を書く 関数本体を作る前にテンプレートを作ると関数本体作成が格段に楽になる 例1 関数`add`の目的と例をデザインレシピにしたがって作成 ```ocaml= (* 目的:ふたつの整数の組 pair を受け取りその要素の和を返す *) (* add : int * int -> int *) let add pair = 0 (* テスト *) let test1 = add (0,0) = 0 let test2 = add (3,5) = 8 let test3 = add (3,-5) = -2 ``` 入力の型が構造データである組になっている 例2 テンプレートを作成  ```ocaml= (* 目的:ふたつの整数の組 pair を受け取りその要素の和を返す *) (* add : int * int -> int *) let add pair = match pair with (a,b) -> 0 ``` ここに出てくる match文 が、引数の型が int * int の場合の組のテンプレート テンプレートをあらかじめ作っておくと、本体を作るときに利用できる値が明確になる 例1の <u>let add pair = 0 </u>だけでは、pairという変数しか使えないが、 例2のようにテンプレートを書いておけば、pairに加えて a と b というパターン変数を使えるようになる 例3 テストプログラムを実行して、テンプレートの match文 に誤りがないかを確認 ```ocaml= #use "/home/miho/ocaml-project/add.ml";; val add : 'a -> int = <fun> val test1 : bool = true val test2 : bool = false val test3 : bool = false ``` 例4 本体作成 ```ocaml= (* 目的:ふたつの整数の組 pair を受け取りその要素の和を返す *) (* add : int * int -> int *) let add pair = match pair with (a,b) -> a + b ``` 例5 テスト ```ocaml= #use "/home/miho/ocaml-project/add.ml";; val test1 : bool = true val test2 : bool = true val test3 : bool = true ``` #### 問題7.3 x座標とy座標の組で表示された平面座標を受け取ったら、x軸について対象な点の座標を返す関数 <b>taisho_x</b>をデザインレシピにしたがって作れ ```ocaml= (*目的:x座標とy座標の組で表示された平面座標を受け取ったら、x軸について対象な点の座標を返す*) (* taisho_x:'a * int -> 'a * int *) let taisho_x ten1 = match ten1 with (a,b) -> (a,-b) (*テスト*) let test1 = taisho_x(3,4)=(3,-4) let test2 = taisho_x(1,2)=(1,-2) #use "/home/miho/ocaml-project/taisho_x.ml";; val taisho_x : 'a * int -> 'a * int = <fun> val test1 : bool = true val test2 : bool = true ``` #### 問題7.4 x座標とy座標の組で表示された平面座標をふたつ受け取ったら、その中点の座標を返す関数 <b>chuten</b>をデザインレシピにしたがって作れ ```ocaml= (*目的:x座標とy座標の組で表示された平面座標をふたつ受け取ったら、その中点の座標を返す*) (* chuten : float * float -> float * float -> float * float *) let chuten ten1 ten2 = match ten1 with ( x1,y1 ) -> ( match ten2 with ( x2,y2 ) -> (( x1 +. x2 ) /. 2.0,( y1 +. y2) /. 2.0)) (*テスト*) let test1 = chuten (2.0,1.0)(6.0,3.0) = (4.0,2.0) let test2 = chuten (3.0,6.0)(5.0,2.0) = (4.0,4.0) #use "/home/miho/ocaml-project/chuten.ml";; val chuten : float * float -> float * float -> float * float = <fun> val test1 : bool = true val test2 : bool = true ``` ## 7.4 パターンマッチの実行方法 ここでは、次のような式を考える <p style="background-color:#DDEEFF;"> match (2 + 3, 4 - 1) with<br> &nbsp;&nbsp;&nbsp;&nbsp;( a , b ) -> a + b</p> (2 + 3, 4 - 1)という組の要素をパターンマッチで取り出し、それらを加えるプログラム ① 式 (2 + 3, 4 - 1) の実行  <p style="background-color:#DDEEFF;"> match ( 5 , 3 ) with<br> &nbsp;&nbsp;&nbsp;&nbsp;( a , b ) -> a + b</p> ② パターンと照合 パターン変数 a が 5 に、b が 3 にマッチする ③ match文全体を -> の右側の式で置き換える 全体が a + b になるが、a と b がそれぞれの値に置き換わるので <p style="background-color:#DDEEFF;"> &nbsp;&nbsp;&nbsp;&nbsp;5 + 3 </p> になり、最後に加算すると 8 が得られる<br> パターンマッチの実行ではパターンマッチの本体に現れるパターン変数をその値に置き換える