<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: #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 h2 {
padding: 0 1.5vw;
margin: 0.0vw 0 2.0vw -2.0vw;
border-left: solid 1.2vw #2980b9;
border-bottom: solid 0.8vw #d7d7d7;
}
</style>
<!-- --------------------------------------------------------------------------------------- -->
#### プログラミングの基礎
# 第10章<br> 再起関数のプログラミング
<br>
<br>
#### 2020年10月
### 武田 雄一郎
---
## 目次
<div class="box">
10.1関数のネスト
10.2リストの最小値を求める関数
10.3局所変数定義
10.4 パターンマッチつき局所変数定義
10.5 ふたつのリストを結合する関数
10.6 ふたつの昇順に並んだリストをマージンする関数
10.7 駅名、駅間リストからの情報取得
</div>
---
## 10.1 関数のネスト
**ネスト**とは関数の中に関数を入れ子のように使うこと。一度で処理するのは難しいため別の関数を作ります。
今回は接頭語を返すprefixをadd_to_each接頭語のリストを受け取ったら、各接頭語の先頭にもう一つ要素を付け加える補助関数使って作る。
---
## 10.1 関数のネスト
テスト
```ocaml=
(* テスト *)
let test1 = add_to_each 1 [] = []
let test2 = add_to_each 1 [[2]] = [[1; 2]]
let test3 = add_to_each 1 [[2]; [2; 3]] = [[1; 2];[1; 2; 3]]
let test4 = add_to_each 1 [[2]; [2; 3]; [2; 3; 4]] = [[1; 2]; [1; 2; 3]; [1; 2; 3; 4]]
let test5 = prefix [] = []
let test6 = prefix [1] = [[1]]
let test7 = prefix [1; 2] = [[1]; [1; 2]]
let test8 = prefix [1; 2; 3; 4] = [[1]; [1; 2]; [1; 2; 3]; [1; 2; 3; 4]]
```
---
## 10.1
接頭語のリストを受け取ったら、各接頭語の先頭にもう一つ要素を付け加える関数add_to_each
```ocaml=
(* 目的:受け取った lst の要素それぞれの先頭に n をくっつける *)
(* add_to_each : int -> int list list -> int list list *)
let rec add_to_each n lst = match lst with
[] -> []
| first :: rest ->[](*add to each n rest*)
```
---
## 10.1
接頭語のリストを受け取ったら、各接頭語の先頭にもう一つ要素を付け加える関数add_to_each
```ocaml=
(* 目的:受け取った lst の要素それぞれの先頭に n をくっつける *)
(* add_to_each : int -> int list list -> int list list *)
let rec add_to_each n lst = match lst with
[] -> []
| first :: rest -> (n :: first) :: add_to_each n rest ;;
val add_to_each : 'a -> 'a list list -> 'a list list = <fun>
```
---
## 10.1
以下、関数prefixのテンプレート
```ocaml=
(* 目的:受け取った lst の接頭語のリストを返す *)
(* prefix : int list -> int list list *)
let rec prefix lst = match lst with
[] -> []
| first :: rest -> [](*prefix rest*)
```
---
## 10.1
テスト8でいうとfirstは1でrest[2; 3; 4]また、prefixで欲しい結果は[[1]; [1; 2]; [1; 2; 3]; [1; 2; 3; 4]]
このことから
add to eachnのnの所がfirstであれば成り立つため
```ocaml=
(* 目的:受け取った lst の接頭語のリストを返す *)
(* prefix : int list -> int list list *)
let rec prefix lst = match lst with
[] -> []
| first :: rest ->[first] :: add_to_each first (prefix rest) ;;
val prefix : 'a list -> 'a list list = <fun
```
---
## 10.1
```ocaml= let test5 = prefix [] = []
let test6 = prefix [1] = [[1]]
let test7 = prefix [1; 2] = [[1]; [1; 2]]
let test8 = prefix [1; 2; 3; 4] = [[1]; [1; 2]; [1; 2; 3]; [1; 2; 3; 4]] ;;
val test5 : bool = true
val test6 : bool = true
val test7 : bool = true
val test8 : bool = true
```
このように複雑な関数を作るときは別の関数を呼び出して処理をさせることもできる。注意として関数を定義するときはそのなかで使う関数はすべて定義されてないといけない。理由はocamlのプログラムはすべて型チェックされるため。
---
## 問題10.1
問題文p94
昇順に並んだリストに整数を挿入する関数insert
```ocaml=
(* テスト *)
let test1 = insert [] 3 = [3]
let test2 = insert [1] 3 = [1; 3]
let test3 = insert [3] 1 = [1; 3]
let test4 = insert [1; 3; 4; 7; 8] 5 = [1; 3; 4; 5; 7; 8]
```
---
## 問題10.1
```ocaml=
(* 目的:昇順に並んでいる lst の正しい位置に n を挿入する *)
(* insert : int list -> int -> int list *)
let rec insert lst n = match lst with
[] -> [n]
| first :: rest ->
if first < n then first :: insert rest n
else n :: lst
(* テスト *)
let test1 = insert [] 3 = [3]
let test2 = insert [1] 3 = [1; 3]
let test3 = insert [3] 1 = [1; 3]
let test4 = insert [1; 3; 4; 7; 8] 5 = [1; 3; 4; 5; 7; 8] ;;
val insert : 'a list -> 'a -> 'a list = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
val test4 : bool = true
```
---
## 問題10.2
問題文p94
```ocaml=
(* 目的:受け取った整数のリスト lst を昇順に並べる *)
(* ins_sort : int list -> int list *)
let rec ins_sort lst = match lst with
[] -> []
| first :: rest -> insert (ins_sort rest) first
(* テスト *)
let test1 = ins_sort [] = []
let test2 = ins_sort [1] = [1]
let test3 = ins_sort [3; 1] = [1; 3]
let test4 = ins_sort [1; 3] = [1; 3]
let test5 = ins_sort [5; 3; 8; 1; 7; 4] = [1; 3; 4; 5; 7; 8] ;;
val ins_sort : 'a list -> 'a list = <fun>
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
val test4 : bool = true
val test5 : bool = true
```
---
## 10.2 リストの最小値を求める関数
最小値を求める関数minimumを作る
以下テンプレート
```ocaml=
(* 目的:受け取った lst の中の最小値を返す *)
(* minimum : int list -> int *)
let rec minimum lst = match lst with
[] -> 0
| first :: rest -> 0 (* minimumu rest *)
```
---
## 10.2
入力が空リストだった場合ここではmax_intを入れる。
理由は空リストでない場合全体の最小値はfirstとrestの中の最小値のちいさい方であり、firstは常にmax_int以下(<=)になるから。
```ocaml=
(* 目的:受け取った lst の中の最小値を返す *)
(* minimum : int list -> int *)
let rec minimum lst = match lst with
[] -> max_int
| first :: rest ->
if first <= minimum rest
then first
else minimum rest ;;
val minimum : int list -> int = <fun>
```
---
## 10.2
```ocaml=
(* テスト *)
let test1 = minimum [3] = 3
let test2 = minimum [1; 2] = 1
let test3 = minimum [3; 2] = 2
let test4 = minimum [3; 2; 6; 4; 1; 8] = 1;;
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
val test4 : bool = true
```
---
## 問題 10.5
問題文p96 ,
p67hyoukaを定義してから
```ocaml=
(* 目的:学生リスト lst の中から最高得点の人を返す *)
(* gakusei_max : gakusei_t list -> gakusei_t *)
let rec gakusei_max lst = match lst with
[] -> {namae = ""; tensuu = min_int; seiseki = ""}
| ({namae = n; tensuu = t; seiseki = s} as gakusei) :: rest ->
match gakusei_max rest with
{namae = n_max; tensuu = t_max; seiseki = s_max} ->
if t_max < t then gakusei
else gakusei_max rest
(* テスト *)
let test1 = gakusei_max lst1 = gakusei2
let test2 = gakusei_max lst2 = gakusei3
let test3 = gakusei_max lst3 = gakusei3
let test4 = gakusei_max lst4 = gakusei1
```
---
## 10.3 局所変数定義
**局所変数**:使える範囲の決まっている変数。
**局所変数定義**:式 1 を実行し、その結果に変数という一時的な名前をつけ,次に式 2 を実行する。その実行の間(のみ)、
**スコープ**局所変数定義された変数の有効範囲
**構文**==let 変数 = 式1 in 式2==
```ocaml=
#let x = 2 in x*x;;
- : int = 4
```
---
## 10.3
例1定義したxと局所変数で定義したx
```ocaml=
#let x = 3 ;;
val x : int = 3
#let x = 2 in x*x ;;
- : int = 4
# x+3 ;;
- : int = 6
```
---
## 10.3
例2
10.2の関数minimumをmin_restという変数を局所的に定義してminimum rest の値をとっておくことにする。
```ocaml=
(* 目的:受け取った lst の中の最小値を返す *)
(* minimum : int list -> int *)
let rec minimum lst = match lst with
[] -> max_int
| first :: rest ->
let min_rest = minimum rest in
if first <= min_rest
then first
else min_rest ;;
val minimum : int list -> int = <fun>
```
---
## 10.3
```ocaml=
(* テスト *)
let test1 = minimum [3] = 3
let test2 = minimum [1; 2] = 1
let test3 = minimum [3; 2] = 2
let test4 = minimum [3; 2; 6; 4; 1; 8] = 1;;
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
val test4 : bool = true
```
このようにminimum restの結果を複数使うときは局所変数定義min_restとしておくと計算し直さなくていいので無駄な計算を省くことができる。
---
## 問題10.6
問題文p99 p67hyoukaを定義してから
```ocaml=
(* 目的:学生リスト lst の中から最高得点の人を返す *)
(* gakusei_max : gakusei_t list -> gakusei_t *)
let rec gakusei_max lst = match lst with
[] -> {namae = ""; tensuu = min_int; seiseki = ""}
| ({namae = n; tensuu = t; seiseki = s} as gakusei) :: rest ->
let rest_max = gakusei_max rest in
match rest_max with
{namae = n_max; tensuu = t_max; seiseki = s_max} ->
if t_max < t then gakusei
else rest_max
(* テスト *)
let test1 = gakusei_max lst1 = gakusei2
let test2 = gakusei_max lst2 = gakusei3
let test3 = gakusei_max lst3 = gakusei3
let test4 = gakusei_max lst4 = gakusei1
```
---
## 10.4 パターンマッチつき局所変数定義
gakusei_t型のレコードのリストを受け取ったらその中に成績がAの人Bの人Cの人Dの人がそれぞれ何人いるかを4つ組にして返す関数shukeiを作る。
以下テンプレート
```ocaml=
(* 学生ひとり分のデータ(名前、点数、成績)を表す型 *)
type gakusei_t = {
namae : string; (* 名前 *)
tensuu : int; (* 点数 *)
seiseki : string; (* 成績 *)
}
(* 目的:学生リスト lst のうち各成績の人数を集計する *)
(* shukei : gakusei_t list -> int * int * int * int *)
let rec shukei lst = match lst with
[] -> (0, 0, 0, 0)
| {namae = n; tensuu = t; seiseki = s} :: rest ->
(0, 0, 0, 0)(*shukei rest)
```
---
## 10.4
局所変数定義を使い集計結果をshukei_restという変数入れる。
理由はshukei_restを参照することで何回もshukei restの結果が使えるため。
集計結果は4つの整数の組なので組の中身を取り出すためmatch withを使う
sの値によって場合分けしその部分の人数を一人増やす
---
## 10.4
```ocaml=
(* 学生ひとり分のデータ(名前、点数、成績)を表す型 *)
type gakusei_t = {
namae : string; (* 名前 *)
tensuu : int; (* 点数 *)
seiseki : string; (* 成績 *)
}
(* 目的:学生リスト lst のうち各成績の人数を集計する *)
(* shukei : gakusei_t list -> int * int * int * int *)
let rec shukei lst = match lst with
[] -> (0, 0, 0, 0)
| {namae = n; tensuu = t; seiseki = s} :: rest ->
let shukei_rest = shukei rest in
match shukei_rest with
(a, b, c, d) -> if s = "A" then (a + 1, b, c, d)
else if s = "B" then (a, b + 1, c, d)
else if s = "C" then (a, b, c + 1, d)
else (a, b, c, d + 1) ;;
type gakusei_t = { namae : string; tensuu : int; seiseki : string; }
val shukei : gakusei_t list -> int * int * int * int = <fun>
```
---
## 10.4
また、局所変数定義の構文変数名のところにパターンを書くことができる。
この場合、shukei_restという変数を(a,b,c,d)というパターンを書いている。
```ocaml=
(* 目的:学生リスト lst のうち各成績の人数を集計する *)
(* shukei : gakusei_t list -> int * int * int * int *)
let rec shukei lst = match lst with
[] -> (0, 0, 0, 0)
| {namae = n; tensuu = t; seiseki = s} :: rest ->
let (a, b, c, d) = shukei rest in
if s = "A" then (a + 1, b, c, d)
else if s = "B" then (a, b + 1, c, d)
else if s = "C" then (a, b, c + 1, d)
else (a, b, c, d + 1)
```
---
## 10.4
```ocaml=
(* テスト *)
let test1 = shukei lst1 = (0, 0, 0, 0)
let test2 = shukei lst2 = (1, 0, 0, 0)
let test3 = shukei lst3 = (0, 2, 0, 0)
let test4 = shukei lst4 = (1, 1, 1, 0)
let test5 = shukei lst5 = (2, 2, 2, 0) ;;
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
val test4 : bool = true
val test5 : bool = true
```
---
## 問題10.7
```ocaml=
(* 人に関する情報を格納するレコード *)
type person_t = {
name : string; (* 名前 *)
shincho : float; (* 身長 *)
taiju : float; (* 体重 *)
tsuki : int; (* 誕生月 *)
hi : int; (* 誕生日 *)
ketsueki : string; (* 血液型 *)
}
(* 目的:人のリスト lst のうち各血液型の人が何人いるかを集計する *)
(* ketsueki_shukei : person_t list -> int * int * int * int *)
let rec ketsueki_shukei lst = match lst with
[] -> (0, 0, 0, 0)
| {name = n; shincho = s; taiju = t; tsuki = ts; hi = h;
ketsueki = k} :: rest ->
let (a, o, b, ab) = ketsueki_shukei rest in
if k = "A" then (a + 1, o, b, ab)
else if k = "O" then (a, o + 1, b, ab)
else if k = "B" then (a, o, b + 1, ab)
else (a, o, b, ab + 1)
type person_t = {
name : string;
shincho : float;
taiju : float;
tsuki : int;
hi : int;
ketsueki : string;
}
val ketsueki_shukei : person_t list -> int * int * int * int = <fun>
```
---
## 問題10.8
p99、101参照
```ocaml=
(* 目的:人のリスト lst のうち最多の血液型を返す *)
(* saita_ketsueki : person_t list -> string *)
let saita_ketsueki lst =
let (a, o, b, ab) = ketsueki_shukei lst in
let saidai = max (max a o) (max b ab) in
if saidai = a then "A"
else if saidai = o then "O"
else if saidai = b then "B"
else "AB"
val saita_ketsueki : person_t list -> string = <fun>
```
---
---
## 10.5 ふたつのリストを結合する関数
ふたつのリスト受け取ったらそれらを返す結合して返す関数appendを作る。
ここでは、最初のリストに対して再起を呼びかけるためlist1に対するmatch文
以下テンプレート
```ocaml=
#(* 目的:lst1 と lst2 を受け取りそれらを結合したリストを返す *)
(* append : 'a list -> 'a list -> 'a list *)
let rec append lst1 lst2 = match lst1 with
[] -> []
| first :: rest -> [] (*append rest lst2 *);;
val append : 'a list -> 'b -> 'c list = <fun>
```
---
## 10.5
```ocaml=
(* テスト *)
let test1 = append [] [] = []
let test2 = append [] [1; 2] = [1; 2]
let test3 = append [1; 2] [] = [1; 2]
let test4 = append [1; 2] [3; 4] = [1; 2; 3; 4]
let test5 = append ["a"; "b"; "c"; "d"; "e"] ["f"; "g"]
= ["a"; "b"; "c"; "d"; "e"; "f"; "g"]
#
```
---
## 10.5
test2の結果をみて最初のケースの結果はlst2となる。
list1全体とlist2をくっつけたリストは再帰呼び出しの結果(restとlist2くっつけたリスト)の先頭にfirstをくっつける。
以下本文
```ocaml=
(* 目的:lst1 と lst2 を受け取りそれらを結合したリストを返す *)
(* append : 'a list -> 'a list -> 'a list *)
let rec append lst1 lst2 = match lst1 with
[] -> lst2
| first :: rest -> first :: append rest lst2
val append : 'a list -> 'a list -> 'a list = <fun>
```
---
## 10.5
```ocaml=
(* テスト *)
let test1 = append [] [] = []
let test2 = append [] [1; 2] = [1; 2]
let test3 = append [1; 2] [] = [1; 2]
let test4 = append [1; 2] [3; 4] = [1; 2; 3; 4]
let test5 = append ["a"; "b"; "c"; "d"; "e"] ["f"; "g"]
= ["a"; "b"; "c"; "d"; "e"; "f"; "g"] ;;
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
val test4 : bool = true
val test5 : bool = true
```
---
## 10.6 ふたつの昇順に並んだリストをマージする関数
ふたつのすでに昇順に並んでいる整数のリストを受け取ったら、それらを合わせてひとつの昇順に並んだリストを返す関数merge。
appendとは違いふたつの引数を同時に考慮する。
ふたつの引数を考えるため一度list1,list2の組を作りパターンマッチさせている。
テストより空が存在する場合3通り、そして、空が存在しないときlist1が短くなる再帰、list2が短くなる再起、両方短くなる再起の3通りがある。
---
## 10.6
```ocaml=
(* テスト *)
let test1 = merge [] [] = []
let test2 = merge [] [1; 2] = [1; 2]
let test3 = merge [1; 2] [] = [1; 2]
let test4 = merge [1; 3] [2; 4] = [1; 2; 3; 4]
let test5 = merge [2; 4] [1; 3] = [1; 2; 3; 4]
let test6 = merge [1; 4] [1; 3] = [1; 1; 3; 4]
```
---
以下テンプレート
```ocaml=
#(* 目的:昇順に並んでいるリスト lst1 と lst2 をマージする *)
(* merge : int list -> int list -> int list *)
let rec merge lst1 lst2 = match (lst1, lst2) with
([], []) -> []
| ([], first2 :: rest2) -> [](*merge lst1 rest2*)
| (first1 :: rest1, []) -> [](*merge lst1 rest2*)
| (first1 :: rest1, first2 :: rest2) ->
if first1 < first2
then [] (* merge lst1 rest2,merge rest1 lst2, merge rest1 rest2*)
else [] (* merge lst1 rest2,merge rest1 lst2, merge rest1 rest2*)
```
---
## 10.6
test4,5,6から両方とも空リストでない場合それぞれの先頭同士を比較しlist1のfirstが小さかった場合first1とrest1とlist2をmergeしたものが結果に、list2のfirstが小さかった場合first2とrest2とlist1をmergeしたものが結果になる。
---
## 10.6
```ocaml=
(* 目的:昇順に並んでいるリスト lst1 と lst2 をマージする *)
(* merge : int list -> int list -> int list *)
let rec merge lst1 lst2 = match (lst1, lst2) with
([], []) -> []
| ([], first2 :: rest2) -> lst2
| (first1 :: rest1, []) -> lst1
| (first1 :: rest1, first2 :: rest2) ->
if first1 < first2
then first1 :: merge rest1 lst2
else first2 :: merge lst1 rest2
val merge : 'a list -> 'a list -> 'a list = <fun>
```
---
## 10.6
```ocaml=
(* テスト *)
let test1 = merge [] [] = []
let test2 = merge [] [1; 2] = [1; 2]
let test3 = merge [1; 2] [] = [1; 2]
let test4 = merge [1; 3] [2; 4] = [1; 2; 3; 4]
let test5 = merge [2; 4] [1; 3] = [1; 2; 3; 4]
let test6 = merge [1; 4] [1; 3] = [1; 1; 3; 4] ;;
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
val test4 : bool = true
val test5 : bool = true
val test6 : bool = true
```
---
## 問題10.9
問題文p105
```ocaml=
(* テスト *)
let test1 = equal_length [] [] = true
let test2 = equal_length [] [1; 2] = false
let test3 = equal_length [1; 2] [] = false
let test4 = equal_length [1; 3] [2; 4] = true
let test5 = equal_length ["a"; "b"; "c"; "d"] [1; 3] = false
let test6 = equal_length ["a"; "b"; "c"; "d"] [1; 3; 2; 4] = true
```
---
## 問題10.9
```ocaml=
(* 目的:lst1 と lst2 の長さが等しいかどうかを判定する *)
(* equal_length : 'a list -> 'a list -> bool *)
let rec equal_length lst1 lst2 = match (lst1, lst2) with
([], []) -> true
| ([], first2 :: rest2) -> false
| (first1 :: rest1, []) -> false
| (first1 :: rest1, first2 :: rest2) -> equal_length rest1 rest2 ;;
val equal_length : 'a list -> 'b list -> bool = <fun>
```
---
## 問題10.9
```ocaml=
let test1 = equal_length [] [] = true
let test2 = equal_length [] [1; 2] = false
let test3 = equal_length [1; 2] [] = false
let test4 = equal_length [1; 3] [2; 4] = true
let test5 = equal_length ["a"; "b"; "c"; "d"] [1; 3] = false
let test6 = equal_length ["a"; "b"; "c"; "d"] [1; 3; 2; 4] = true ;;
val test1 : bool = true
val test2 : bool = true
val test3 : bool = true
val test4 : bool = true
val test5 : bool = true
val test6 : bool = true
```
---
## 10.7 駅名、駅間リストからの情報の取得
メトロネットワーク最短経路問題を解く上で必要となるいくつかの関数を作成
---
## 10.7(問題10.10)
駅名リストから情報を取り出す関数romaji_to_kanji
問題文p105 9.9定義後
```ocaml=
(* 目的:ローマ字の駅名を漢字に直す *)
(* romaji_to_kanji : string -> ekimei_t list -> string *)
#use "metro.ml"
let rec romaji_to_kanji r0 ekimei_list = match ekimei_list with
[] -> ""
| {kanji = k; kana = a; romaji = r; shozoku = s} :: rest ->
if r0 = r then k
else romaji_to_kanji r0 rest
```
---
## 10.7(問題10.11)
駅間リストから情報を取り出す関数get_ekikan_kyori
(get_ekikan_kyoriは駅名をふたつ受け取け、その間の距離を返す。)
問題文p105 9.10定義後
```ocaml=
(* 目的:ふたつの駅の間の距離を求める *)
(* get_ekikan_kyori : string -> string -> ekikan_t list -> float *)
#use "metro.ml"
let rec get_ekikan_kyori eki1 eki2 lst = match lst with
[] -> 0.0
| {kiten = k; shuten = s; keiyu = y; kyori = r; jikan = j} :: rest ->
if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k)
then 0.0
else 0.0
```
---
## 10.7(問題10.11)
```ocaml=
(* 目的:ふたつの駅の間の距離を求める *)
(* get_ekikan_kyori : string -> string -> ekikan_t list -> float *)
#use "metro.ml"
let rec get_ekikan_kyori eki1 eki2 lst = match lst with
[] -> infinity
| {kiten = k; shuten = s; keiyu = y; kyori = r; jikan = j} :: rest ->
if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k)
then r
else get_ekikan_kyori eki1 eki2 rest
```
---
## 10.7(問題10.12)
romaji_to_kanjiとget_ekikan_kyoriを使い関数を作る
問題文p106
```ocaml=
(* テスト *)
let test1 = kyori_wo_hyoji "myougadani" "shinotsuka" = "myougadani という駅は存在しません"
let test2 = kyori_wo_hyoji "tokyo" "ootemachi" = "ootemachi という駅は存在しません"
let test3 = kyori_wo_hyoji "myogadani" "ikebukuro" = "茗荷谷と池袋はつながっていません"
let test4 = kyori_wo_hyoji "myogadani" "shinotsuka" = "茗荷谷から新大塚までは 1.2 キロです"
let test5 = kyori_wo_hyoji "tokyo" "otemachi" = "東京から大手町までは 0.6 キロです"
```
---
## 10.7(問題10.12)
```ocaml=
(*kyori_wo_hyoji: string -> string -> string*)
#use "metro.ml"
#use "ex10.10.ml"
#use "ex10.11.ml"
(* 目的:ふたつの駅の間の距離を文字列で表現する *)
(*kyori_wo_hyoji: string -> string -> string*)
let kyori_wo_hyoji romaji1 romaji2 =
if romaji_to_kanji romaji1 global_ekimei_list = "" then ""
else if romaji_to_kanji romaji2 global_ekimei_list = "" then ""
else if get_ekikan_kyori (romaji_to_kanji romaji1 global_ekimei_list) romaji_to_kanji (romaji2 global_ekimei_list) = infinity then ""
else ""
```
---
## 10.7(問題10.12)
```ocaml=
(* 目的:ふたつの駅の間の距離を文字列で表現する *)
(*kyori_wo_hyoji: string -> string -> ekikan_t list -> string*)
#use "metro.ml"
#use "ex10.10.ml"
#use "ex10.11.ml"
(* 目的:ふたつの駅の間の距離を文字列で表現する *)
let kyori_wo_hyoji romaji1 romaji2 =
let kanji1 = romaji_to_kanji romaji1 global_ekimei_list in
if kanji1 = "" then romaji1 ^ " という駅は存在しません"
else let kanji2 = romaji_to_kanji romaji2 global_ekimei_list in
if kanji2 = "" then romaji2 ^ " という駅は存在しません"
else let kyori = get_ekikan_kyori kanji1 kanji2 global_ekikan_list in
if kyori = infinity
then kanji1 ^ "と" ^ kanji2 ^ "はつながっていません"
else kanji1 ^ "から" ^ kanji2 ^ "までは " ^
string_of_float kyori ^ " キロです"
```
{"metaMigratedAt":"2023-06-15T15:01:09.908Z","metaMigratedFrom":"YAML","title":"HackMD presentation Sample2","breaks":true,"slideOptions":"{\"theme\":\"white\",\"slideNumber\":\"c/t\",\"center\":false,\"transition\":\"none\",\"keyboard\":true,\"width\":\"93%\",\"height\":\"100%\"}","contributors":"[{\"id\":\"537a978a-04ea-4213-b7f1-fe683925e1f0\",\"add\":29953,\"del\":8076}]"}