<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.8;
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: #2980b9;}
.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: #EEE; 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: #f5f5f5;
}
.reveal blockquote:before{
position: absolute;
top: 0.1vw;
left: 1vw;
content: "\f10d";
font-family: FontAwesome;
color: #2980b9;
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>
/* specific design */
.reveal h1 {
margin: 0% -100%;
padding: 2% 100% 4% 100%;
color: #fff;
background: #fffa5e; /* fallback for old browsers */
background: linear-gradient(-45deg, #f7f439, #54ffa4, #23A6D5, #238ed5);
background-size: 200% 200%;
animation: Gradient 60s ease infinite;
}
@keyframes Gradient {
0% {background-position: 0% 50%}
50% {background-position: 100% 50%}
100% {background-position: 0% 50%}
}
.reveal h2 {
text-align: center;
margin: -5% -50% 2% -50%;
padding: 4% 10% 1% 10%;
color: #fff;
background: #fffa5e; /* fallback for old browsers */
background: -webkit-linear-gradient(to right, #c74646, #fffa5e); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(to right, #c74646, #fffa5e); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
}
</style>
<!-- --------------------------------------------------------------------------------------- -->
# 第7章 <br>組とパターンマッチ
<br>
<br>
#### 2020/10/09
### 201803407 有田健一郎
---
## 組とは
<div class="box">
**いくつかのデータを並べてひとつのデータにしたもの**である。
<br>わかりやすい例は、ふたつの実数を並べて作った**2次元平面上の点**が挙げられる。数学における2次元平面上の点は、2つの実数 $x$ と $y$ を使って $(x,y)$ と表現される。内部で $x$ と $y$ という**2つの実数**を使っているが、**全体としてはひとつの点**を表している。
</div>
---
## 組の構文
OCamlにおいて、**組**は要素の値を**コンマで区切って**表現する。
```ocaml=
# (3.14, 1.414) ;;
- : float * float = (3.14, 1.414)
#
```
組は**違う型の要素**を並べても、また**3つ以上の要素**を並べても構わない。
```ocaml=
# (3, true) ;;
- : int * bool = (3, true)
#
```
---
## 組の構文
次の例は3つの型を合わせて組にしたものである。
```ocaml=
# (3.14, 1, "abc") ;;
- : float * int * string = (3.14, 1, "abc")
#
```
組の要素は基本的な型である必要はない。例として、**組の組**といった形式でも作成することができる。
```ocaml=
# ((3.14, 1), "abc") ;;
- : (float * int) * string = ((3.14, 1), "abc")
#
```
これは「実数と整数の組」と「文字列」という**2つの要素を合わせた組**です。1つ前の例で出てきた(3.14, 1, "abc")とは**全く別のデータ**である。
---
## 組の構文(補足)
これまでの組の例では括弧を使って表していたが、コンマさえあれば括弧を省略しても組を使うことは可能である。
```ocaml=
# 3.14, 1.414 ;;
- : float * float = (3.14, 1.414)
#
```
---
## パターンマッチとは
先ほど説明した組は**複数のデータを一つにまとめる**といった内容でしたが、まとめた中身を取り出さなければ意味がない。組に限らず複数のデータからできているデータの中身を取り出すために**パターンマッチ:パターンの照合**を使う。
パターンマッチの構文のもっとも簡単な形は以下のような形である。
<br>
<div class="box">
match 式 with
パターン -> 式
</div>
---
## 具体例
```ocaml=
# match (3, 5) with
(a, b) -> a + b ;;
- : int = 8
#
```
このプログラムは、(3, 5)という組からパターンマッチを使って要素を取り出し、それらを加えた結果を返す。(a, b)というのが二つの値の組を表すパターンであり、ここでのaとbは**パターン変数**と呼ばれ、構造データの要素を取り出すのに使われる。
---
## 具体例2
```ocaml=
# let add pair = match pair with
(a, b) -> a + b ;;
val add : int * int -> int = <fun>
#
```
先ほどの具体例と変わり、関数addを定義し、組の作成と要素を取り出す位置は別の**場所**で行います。
この関数を使って組(3, 5)の要素を加えるとすれば以下のようにする。
```ocaml=
# add (3, 5) ;;
- : int = 8
#
```
---
## 別の記述方法
先ほどのmatchを使う文を以下のように記述することも可能である。
```ocaml=
# let add (a, b) = a + b ;;
val add : int * int -> int = <fun>
#
```
(a, b)というパターンが引数の役割を一緒に担っている。
<br>**※デザインレシピに従った系統的なプログラミングをめざしているため、基本的に引数に直接パターンを書く方法は使わない。**
---
## 制限
match文や関数の引数のパターンを書く際には**パターン変数はお互いに異なってなくてはならない**という**制限**がある。
以下に具体例を示す。
```ocaml=
# let f pair = match pair with
(a, a) -> a + a ;;
this variable is bound several times in this matching
#
```
パターン変数は異なっていないといけないため、このように記述することはできない。
---
## 同じ関数
先ほどまで作成していた関数addはaとbを組として一度に受け取るものであった。しかし、二つの整数を加えるだけなら次のような方法でほぼ同じ関数を作成できる。
```ocaml=
# let add2 a b = a + b ;;
val add2 : int -> int -> int = <fun>
#
```
この関数はaとbを一度に受け取るのではなく、別々に受け取り、それらの和を返す。
```ocaml=
# add2 3 5 ;;
- : int = 8
#
```
---
## デザインレシピ
ここまでの流れからデザインレシピを設計する。
```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
```
addの形を考えると、入力の型が構造データである**組**になっており、入力の型がint * intなので次のようなプログラムになる。
---
## デザインレシピ
```ocaml=
(* 目的:ふたつの整数の組pairを受け取りその要素の和を返す *)
(* add : int * int -> int *)
let add pair = match pair with
(a, b) -> 0
```
このように記述しておくことでpairに加えてaとbというパターン変数を使えるようになる。
---
## デザインレシピ(テスト)
この時点でテストプログラムを実行して誤りがないか確認する。
```ocaml=
# #use "add.ml" ;;
val add : int * int -> int = <fun>
val test1 : bool = true
val test2 : bool = false
val test3 : bool = false
```
結果は不一致ではあるが、エラーなく無事に実行できたため、ここからはこれをテンプレートとし、試行錯誤しながらプログラムを変更していく。
---
## デザインレシピ(完成)
最終的なプログラムは以下のようになる。
```ocaml=
(* 目的:ふたつの整数の組pairを受け取りその要素の和を返す *)
(* add : int * int -> int *)
let add pair = match pair with
(a, b) -> a + b
```
```ocaml=
# #use "add.ml" ;;
val add : int * int -> int = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
```
---
## パターンマッチの実行方法
最後に、パターンマッチの実行方法を見ておく。
次のような式を考える。
<div class="box">
match (2 + 3, 4 - 1) with
(a, b) -> a + b
</div>
結果として次のようになる。
<div class="box">
match (5, 3) with
(a, b) -> a + b
</div>
最終的には5 + 3され結果は8が得られる。
---
## 問題7.1
国語、数学、英語、理科、社会の5教科の点数が与えられたら、
その合計点と平均点を組にして返す関数goukei_to_heikinを定義せよ。
---
## 問題7.1 解答
```ocaml=
let goukei_to_heikin japanese math english science society =
(japanese + math + english + science + society,
(japanese + math + english + science + society) / 5)
let test1 = goukei_to_heikin 80 80 80 80 80 = (400, 80)
let test2 = goukei_to_heikin 90 85 95 90 90 = (450, 90)
let test3 = goukei_to_heikin 50 60 70 80 90 = (350, 70)
```
実行結果は以下のようになった。
```ocaml=
val goukei_to_heikin : int -> int -> int -> int -> int -> int * int = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
```
---
## 問題7.2
名前と成績の組を受け取ったら、「〇〇さんの評価は△△です」という文字列を返す関数seisekiを定義せよ。
---
## 問題7.2 解答
```ocaml=
let seiseki pair = match pair with
(name, value) -> name ^ "さんの評価は" ^ value ^ "です。"
let test1 = seiseki ("椎木", "秀") = "椎木さんの評価は秀です。"
let test2 = seiseki ("山本", "優") = "山本さんの評価は優です。"
let test3 = seiseki ("山田", "良") = "山田さんの評価は良です。"
```
実行結果は以下のようになった。
```ocaml=
val seiseki : string * string -> string = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
```
---
## 問題7.3
x座標とy座標の組で表された平面座標を受け取ったら、x軸について対称な点の座標を返す関数taisho_xをデザインレシピにしたがって作れ。
---
## 問題7.3 目的
```ocaml=
(* 目的:x座標とy座標の組で表された平面座標を受け取ったら、
x軸について対称な点の座標を返す関数taisho_x *)
(* taisho_x : float * float -> float * float *)
let taisho_x point = match point with
(x, y) -> (0.0, 0.0)
let test1 = taisho_x (0.0, 0.0) = (0.0, 0.0)
let test2 = taisho_x (2.0, 4.0) = (2.0, -4.0)
let test3 = taisho_x (6.2, -8.4) = (6.2, 8.4)
```
---
## 問題7.3 テスト
```ocaml=
val taisho_x : 'a * 'b -> float * float = <fun>
val test1 : bool = true
val test2 : bool = false
val test3 : bool = false
```
---
## 問題7.3 解答
```ocaml=
(* 目的:x座標とy座標の組で表された平面座標を受け取ったら、
x軸について対称な点の座標を返す関数taisho_x *)
(* taisho_x : float * float -> float * float *)
let taisho_x point = match point with
(x, y) -> (x, -. y)
let test1 = taisho_x (0.0, 0.0) = (0.0, 0.0)
let test2 = taisho_x (2.0, 4.0) = (2.0, -4.0)
let test3 = taisho_x (6.2, -8.4) = (6.2, 8.4)
```
---
## 問題7.3 結果
```ocaml=
val taisho_x : 'a * 'b -> float * float = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
```
---
## 問題7.4
x座標とy座標の組で表された平面座標を**ふたつ**受け取ったら、その中点の座標を返す関数chutenをデザインレシピにしたがって作れ。
---
## 問題7.4 目的
```ocaml=
(* 目的:x座標とy座標の組で表された平面座標をふたつ受け取ったら、
その中点の座標を返す関数chuten *)
(* chuten : float * float -> float * float -> float * float *)
let chuten point1 point2 = match point1 with
(x1, y1) -> match point2 with
(x2, y2) -> (0.0, 0.0)
let test1 = chuten (0.0, 0.0) (0.0, 0.0) = (0.0, 0.0)
let test2 = chuten (5.0, 2.0) (3.0, 4.0) = (4.0, 3.0)
let test3 = chuten (-6.0, -1.5) (3.0, -1.3) = (-1.5, -1.4)
```
---
## 問題7.4 テスト
```ocaml=
val chuten : 'a * 'b -> 'c * 'd -> float * float = <fun>
val test1 : bool = true
val test2 : bool = false
val test3 : bool = false
```
---
## 問題7.4 解答
```ocaml=
(* 目的:x座標とy座標の組で表された平面座標をふたつ受け取ったら、
その中点の座標を返す関数chuten *)
(* chuten : float * float -> float * float -> float * float *)
let chuten point1 point2 = match point1 with
(x1, y1) -> match point2 with
(x2, y2) -> ((x1 +. x2) /. 2.0, (y1 +. y2) /. 2.0)
let test1 = chuten (0.0, 0.0) (0.0, 0.0) = (0.0, 0.0)
let test2 = chuten (5.0, 2.0) (3.0, 4.0) = (4.0, 3.0)
let test3 = chuten (-6.0, -1.5) (3.0, -1.3) = (-1.5, -1.4)
```
---
## 問題7.4 結果
```ocaml=
val chuten : 'a * 'b -> 'c * 'd -> float * float = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
```
---
<br>
<br>
<br>
<br>
# ご清聴ありがとうございました!!
{"metaMigratedAt":"2023-06-15T13:43:36.590Z","metaMigratedFrom":"YAML","title":"第7章 組とパターンマッチ","breaks":true,"slideOptions":"{\"theme\":\"white\",\"slideNumber\":\"c/t\",\"center\":false,\"transition\":\"none\",\"keyboard\":true,\"width\":\"93%\",\"height\":\"100%\"}","contributors":"[{\"id\":\"a0de3d6a-cf71-4961-a3bb-e324e7c21a77\",\"add\":12017,\"del\":1205},{\"id\":\"3c451922-f763-4317-80af-a2ca3cf846be\",\"add\":22,\"del\":23}]"}