《プログラミングの基礎》をReScriptで読む 第15章

[《プログラミングの基礎》](https://www.amazon.co.jp/dp/4781911609/ "Amazonへのリンク")はとても良い本です。
サンプルプログラムをReScriptで書いて、プログラミングの基礎とReScriptを学びます。
# 環境
* macOS Sonoma(バージョン 14.4.1)
* ReScript 11.1.0-rc.8
* @rescript/core 1.2.0
# 第15章
```ReScript:Ex15_2.res
// 目的：m > n > 0 なる自然数 m と n の最大公約数を求める
// gcd : int -> int -> int
let rec gcd = (m, n) =>
  if n == 0 {m} else {gcd(n, mod(m, n))}
 
// テスト
Console.log(gcd(7, 5) == 1)
Console.log(gcd(30, 18) == 6)
Console.log(gcd(36, 24) == 12)
```
```ReScript:Ex15_3.res
// 目的：受け取ったリストを反転する
// reverse : 'a list -> 'a list
let rec reverse = (lst) => switch lst {
| list{} => list{}
| list{first, ...rest} => list{...reverse(rest), first}
}
// テスト
Console.log(reverse(list{}) == list{})
Console.log(reverse(list{1, 2, 3, 4, 5}) == list{5, 4, 3, 2, 1})
Console.log(reverse(list{"春", "夏", "秋", "冬"}) == list{"冬", "秋", "夏", "春"})

// 目的：2 から n までの自然数を受け取り 2 から n までの素数を返す
// sieve : int list -> int list
let rec sieve = (lst) => switch lst {
| list{} => list{}
| list{first, ...rest} =>
    list{first, ...sieve(List.filter(rest, (x) => mod(x, first) != 0))}
}
 
// テスト
Console.log(sieve(list{2, 3, 4, 5, 6, 7, 8, 9, 10}) == list{2, 3, 5, 7})
 
// 目的：2 から受け取った自然数 n までの自然数のリストを返す
// two_to_n : int -> int list
let two_to_n = (n) => {
  // 目的：受け取った自然数 n から 2 までの自然数のリストを返す
  // n_to_two : int -> int list
  let rec n_to_two = (n) => switch n {
  | 2 => list{2}
  | _ => list{n, ...n_to_two(n - 1)}
  }
  reverse(n_to_two(n))
}

Console.log(two_to_n(10) == list{2, 3, 4, 5, 6, 7, 8, 9, 10})

// 目的：2 から受け取った自然数 n までの素数を返す
// prime : int -> int list
let prime = (n) => sieve(two_to_n(n))
 
// テスト
Console.log(prime(10) == list{2, 3, 5, 7})
```
```ReScript:Ex15_4.res
open Ex12_1

// 目的：受け取った駅のリストを、最短距離最小の駅とそれ以外に分離する
// saitan_wo_bunri : eki_t list -> eki_t * eki_t list
let rec saitan_wo_bunri = (eki_list) => switch eki_list {
| list{} => ({namae: "", saitan_kyori: Float.Constants.positiveInfinity, temae_list: list{}}, list{})
| list{first, ...list{}} => (first, list{})
| list{first, ...rest} => {
    let (p, v) = saitan_wo_bunri(rest) 
    switch(first, p) {
	  | ({namae: _, saitan_kyori: fs, temae_list: _}, 
	     {namae: _, saitan_kyori: ss, temae_list: _}) => 
  	  if fs < ss {(first, list{p, ...v})}
	    else {(p, list{first, ...v})}
    }
  }
}

// 駅の例
let eki1 = {namae: "池袋", saitan_kyori: Float.Constants.positiveInfinity, temae_list: list{}}
let eki2 = {namae:"新大塚", saitan_kyori: 1.2, temae_list: list{"新大塚", "茗荷谷"}}
let eki3 = {namae:"茗荷谷", saitan_kyori: 0., temae_list : list{"茗荷谷"}}
let eki4 = {namae:"後楽園", saitan_kyori: Float.Constants.positiveInfinity, temae_list: list{}}
 
// 駅リストの例
let lst = list{eki1, eki2, eki3, eki4}
 
// テスト
Console.log(saitan_wo_bunri(lst) == (eki3, list{eki1, eki2, eki4}))
```
```ReScript:Ex15_5.res
open Ex12_1

// 目的：受け取った駅のリストを、最短距離最小の駅とそれ以外に分離する
// saitan_wo_bunri : eki_t list -> eki_t * eki_t list
let saitan_wo_bunri = (eki_list) => switch eki_list {
| list{} => ({namae: "", saitan_kyori: Float.Constants.positiveInfinity, temae_list: list{}}, list{})
| list{first, ...rest} =>
    Js.List.foldRight((first, (p, v)) => switch(first, p) {
		|	({namae: _, saitan_kyori: fs, temae_list: _},
			 {namae: _, saitan_kyori: ss, temae_list: _}) => 
			  if fs < ss {(first, list{p, ...v})} 
			  else {(p, list{first, ...v})}
    },
		rest,
		(first, list{}))
}

// 駅の例
let eki1 = {namae: "池袋", saitan_kyori: Float.Constants.positiveInfinity, temae_list: list{}}
let eki2 = {namae: "新大塚", saitan_kyori: Float.Constants.positiveInfinity, temae_list: list{"新大塚", "茗荷谷"}}
let eki3 = {namae: "茗荷谷", saitan_kyori: 0., temae_list: list{"茗荷谷"}}
let eki4 = {namae: "後楽園", saitan_kyori: Float.Constants.positiveInfinity, temae_list: list{}}

// 駅リストの例
let lst = list{eki1, eki2, eki3, eki4}
 
// テスト
Console.log(saitan_wo_bunri(lst) == (eki3, list{eki2, eki1, eki4}))
```