0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Posted at

《プログラミングの基礎》はとても良い本です。
サンプルプログラムをReScriptで書いて、プログラミングの基礎とReScriptを学びます。

環境

  • macOS Sonoma(バージョン 14.4.1)
  • ReScript 11.1.0-rc.8
  • @rescript/core 1.2.0

第10章

OCamlの局所変数定義let inは、ReScriptでは{}でいけます。

Ex10_1.res
// 目的:昇順に並んでいる lst の正しい位置に n を挿入する
// insert : int list -> int -> int list
let rec insert = (lst, n) => switch lst {
| list{} => list{n}
| list{first, ...rest} =>
    if first < n {list{first, ...insert(rest ,n)}}
    else {list{n, ...lst}}
}

// テスト
Console.log(insert(list{}, 3) == list{3})
Console.log(insert(list{1}, 3) == list{1, 3})
Console.log(insert(list{3}, 1) == list{1, 3})
Console.log(insert(list{1, 3, 4, 7, 8}, 5) == list{1, 3, 4, 5, 7, 8})
Ex10_2.res
open Ex10_1 //insertの定義

// 目的:受け取った整数のリスト lst を昇順に並べる
// ins_sort : int list -> int list
let rec ins_sort = (lst) => switch lst { 
| list{} => list{} 
| list{first, ...rest} => insert(ins_sort(rest), first) 
}

// テスト
Console.log(ins_sort(list{}) == list{})
Console.log(ins_sort(list{1}) == list{1})
Console.log(ins_sort(list{3, 1}) == list{1, 3}) 
Console.log(ins_sort(list{1, 3}) == list{1, 3})
Console.log(ins_sort(list{5, 3, 8, 1, 7, 4}) == list{1, 3, 4, 5, 7, 8}) 
Ex10_3.res
type gakusei_t = {
  namae: string,
  tensuu: int,
  seiseki: string
}

let gakusei1 = {namae: "nakamura", tensuu: 90, seiseki: "A"}
let gakusei2 = {namae: "miyahara", tensuu:80, seiseki: "A"} 
let gakusei3 = {namae: "sato", tensuu:75, seiseki: "B"}
let gakusei4 = {namae: "idehara", tensuu: 70, seiseki: "B"}
let gakusei5 = {namae: "tsubata", tensuu: 65, seiseki: "C"}
let gakusei6 = {namae: "asai", tensuu:60, seiseki: "C"}
 
let lst1 = list{}
let lst2 = list{gakusei2}
let lst3 = list{gakusei3, gakusei4}
let lst4 = list{gakusei4, gakusei3}
let lst5 = list{gakusei4, gakusei1, gakusei6, gakusei5, gakusei2, gakusei3}
 
// 目的:昇順に並んでいる lst の正しい位置に gakusei を挿入する
// gakusei_insert : gakusei_t list -> gakusei_t -> gakusei_t list
let rec gakusei_insert = (lst, gakusei0) => switch lst {
| list{} => list{gakusei0}
| list{{namae: n, tensuu: t, seiseki: s}, ...rest} =>
  switch gakusei0 {
  | {namae: _, tensuu: t0, seiseki: _} =>
      if t < t0 {list{{namae: n, tensuu: t, seiseki: s}, ...gakusei_insert(rest, gakusei0)}}
      else {list{gakusei0, ...lst}}
  }
}

// テスト
Console.log(gakusei_insert(list{}, gakusei2) == list{gakusei2})
Console.log(gakusei_insert(list{gakusei4}, gakusei3) == list{gakusei4, gakusei3})
Console.log(gakusei_insert(list{gakusei3}, gakusei4) == list{gakusei4, gakusei3})
Console.log(gakusei_insert(list{gakusei6, gakusei5, gakusei3, gakusei2, gakusei1}, gakusei4) == list{gakusei6, gakusei5, gakusei4, gakusei3, gakusei2, gakusei1})

// 目的:受け取った学生のリスト lst を点数の順に並べる
// gakusei_ins_sort : gakusei_t list -> gakusei_t list
let rec gakusei_ins_sort = (lst) => switch lst {
| list{} => list{}
| list{first, ...rest} => gakusei_insert(gakusei_ins_sort(rest), first)
}

// テスト
Console.log(gakusei_ins_sort(lst1) == list{})
Console.log(gakusei_ins_sort(lst2) == list{gakusei2})
Console.log(gakusei_ins_sort(lst3) == list{gakusei4, gakusei3})
Console.log(gakusei_ins_sort(lst4) == list{gakusei4, gakusei3})
Console.log(gakusei_ins_sort(lst5) == list{gakusei6, gakusei5, gakusei4, gakusei3, gakusei2, gakusei1})
Ex10_4.res
// 人に関する情報を格納するレコード
open Ex08_3
open Ex08_4

// person_t 型のリストの例
let lst1 = list{}
let lst2 = list{person1}
let lst3 = list{person1, person2}
let lst4 = list{person2, person1}
let lst5 = list{person3, person1, person2}
 
// 目的:昇順に並んでいる lst の正しい位置に person を挿入する
// person_insert : person_t list -> person_t -> person_t list
let rec person_insert = (lst, person0) => switch lst {
| list{} => list{person0}
| list{{name: n, shincho: s, taiju: t, tsuki: ts, hi: h, ketsueki: k}, ...rest} =>
  switch person0 {
  | {name: n0, shincho: _, taiju: _, tsuki: _, hi: _, ketsueki: _} =>
    if n < n0 {list{{name: n, shincho: s, taiju: t, tsuki: ts, hi: h, ketsueki: k}, ...person_insert(rest, person0)}}
    else {list{person0, ...lst}}
  }
}
 
//テスト
Console.log(person_insert(list{}, person1) == list{person1})
Console.log(person_insert(list{person2}, person1) == list{person2, person1})
Console.log(person_insert(list{person1}, person2) == list{person2, person1})
Console.log(person_insert(list{person2, person1}, person3) == list{person3, person2, person1})

// 目的:受け取った人のリスト lst を名前の順に並べる
// person_ins_sort : person_t list -> person_t list
let rec person_ins_sort = (lst) => switch lst {
| list{} => list{}
| list{first, ...rest} => person_insert(person_ins_sort(rest), first)
}

//テスト
Console.log(person_ins_sort(lst1) == list{})
Console.log(person_ins_sort(lst2) == list{person1})
Console.log(person_ins_sort(lst3) == list{person2, person1})
Console.log(person_ins_sort(lst4) == list{person2, person1})
Console.log(person_ins_sort(lst5) == list{person3, person2, person1})
Ex10_5.res
type gakusei_t = {
  namae: string,
  tensuu: int,
  seiseki: string
}

// 学生のデータの例
let gakusei1 = {namae: "nakamura", tensuu:90, seiseki: "A"}
let gakusei2 = {namae: "miyahara", tensuu:80, seiseki: "A"}
let gakusei3 = {namae: "sato", tensuu:75, seiseki: "B"}
let gakusei4 = {namae: "idehara", tensuu:70, seiseki: "B"}
let gakusei5 = {namae: "tsubata", tensuu:65, seiseki: "C"}
let gakusei6 = {namae: "asai", tensuu:60, seiseki: "C"}
 
// 学生のリストの例
let lst1 = list{gakusei2}
let lst2 = list{gakusei3, gakusei4}
let lst3 = list{gakusei4, gakusei3}
let lst4 = list{gakusei4, gakusei1, gakusei6, gakusei5, gakusei2, gakusei3}
 
// 目的:学生リスト lst の中から最高得点の人を返す
// gakusei_max : gakusei_t list -> gakusei_t
let rec gakusei_max = (lst) => switch lst {
| list{} => {namae: "", tensuu: Js.Int.min, seiseki: ""}
| list{{namae: n, tensuu: t, seiseki: s}, ...rest} =>
    switch gakusei_max(rest) {
    |  {namae: _, tensuu: t_max, seiseki: _} => 
      if t_max < t {{namae: n, tensuu: t, seiseki: s}}
      else {gakusei_max(rest)}
    }
}
 
// テスト
Console.log(gakusei_max(lst1) == gakusei2)
Console.log(gakusei_max(lst2) == gakusei3)
Console.log(gakusei_max(lst3) == gakusei3)
Console.log(gakusei_max(lst4) == gakusei1)
Ex10_6.res
type gakusei_t = {
  namae: string,
  tensuu: int,
  seiseki: string
}

// 学生のデータの例
let gakusei1 = {namae: "nakamura", tensuu:90, seiseki: "A"}
let gakusei2 = {namae: "miyahara", tensuu:80, seiseki: "A"}
let gakusei3 = {namae: "sato", tensuu:75, seiseki: "B"}
let gakusei4 = {namae: "idehara", tensuu:70, seiseki: "B"}
let gakusei5 = {namae: "tsubata", tensuu:65, seiseki: "C"}
let gakusei6 = {namae: "asai", tensuu:60, seiseki: "C"}
 
// 学生のリストの例
let lst1 = list{gakusei2}
let lst2 = list{gakusei3, gakusei4}
let lst3 = list{gakusei4, gakusei3}
let lst4 = list{gakusei4, gakusei1, gakusei6, gakusei5, gakusei2, gakusei3}
 
// 目的:学生リスト lst の中から最高得点の人を返す
// gakusei_max : gakusei_t list -> gakusei_t
let rec gakusei_max = (lst) => switch lst {
| list{} => {namae: "", tensuu: Js.Int.min, seiseki: ""}
| list{{namae: n, tensuu: t, seiseki: s}, ...rest} => {
    let rest_max = gakusei_max(rest)
    switch rest_max {
    | {namae: _, tensuu: t_max, seiseki: _} =>
  	  if t_max < t {{namae: n, tensuu: t, seiseki: s}} else {rest_max}
    }
  }
}

// テスト
Console.log(gakusei_max(lst1) == gakusei2)
Console.log(gakusei_max(lst2) == gakusei3)
Console.log(gakusei_max(lst3) == gakusei3)
Console.log(gakusei_max(lst4) == gakusei1)
Ex10_7.res
// 人に関する情報を格納するレコード
open Ex08_3
open Ex08_4

// person_t list 型のデータの例
let lst1 = list{}
let lst2 = list{person1}
let lst3 = list{person2}
let lst4 = list{person1, person2, person3}
let lst5 = list{person2, person1, person1}
 
// 目的:人のリスト lst のうち各血液型の人が何人いるかを集計する
// ketsueki_shukei : person_t list -> int * int * int * int
let rec ketsueki_shukei = (lst) => switch lst {
| list{} => (0, 0, 0, 0)
| list{{name: _, shincho: _, taiju: _, tsuki: _, hi: _, ketsueki: k}, ...rest} => {
    let (a, o, b, ab) = ketsueki_shukei(rest)
    if k == "A" {(a + 1, o, b, ab)}
    else if k == "O" {(a, o + 1, b, ab)}
    else if k== "B" {(a, o, b + 1, ab)}
    else {(a, o, b, ab + 1)}
  }
}

// テスト
Console.log(ketsueki_shukei(lst1) == (0, 0, 0, 0))
Console.log(ketsueki_shukei(lst2) == (1, 0, 0, 0))
Console.log(ketsueki_shukei(lst3) == (0, 0, 1, 0))
Console.log(ketsueki_shukei(lst4) == (1, 1, 1, 0))
Console.log(ketsueki_shukei(lst5) == (2, 0, 1, 0))
Ex10_8.res
open Ex08_3
open Ex08_4

// person_t list 型のデータの例
let lst1 = list{person1}
let lst2 = list{person2}
let lst3 = list{person1, person2, person3}
let lst4 = list{person2, person1, person1}

// 目的:人のリスト lst のうち各血液型の人が何人いるかを集計する
// ketsueki_shukei : person_t list -> int * int * int * int
let rec ketsueki_shukei = (lst) => switch lst {
| list{} => (0, 0, 0, 0)
| list{{name: _, shincho: _, taiju: _, tsuki: _, hi: _, ketsueki: k}, ...rest} => {
    let (a, o, b, ab) = ketsueki_shukei(rest)
    if k == "A" {(a + 1, o, b, ab)}
    else if k == "O" {(a, o + 1, b, ab)}
    else if k== "B" {(a, o, b + 1, ab)}
    else {(a, o, b, ab + 1)}
  }
}

// 目的:人のリスト lst のうち最多の血液型を返す
// saita_ketsueki : person_t list -> string
let saita_ketsueki = (lst) => {
  let (a, o, b, ab) = ketsueki_shukei(lst)
  let saidai = Math.Int.max(Math.Int.max(a, o), Math.Int.max(b, ab))
  if saidai == a {"A"}
  else if saidai == o {"O"}
  else if saidai == b {"B"}
  else {"AB"}
}

// テスト
Console.log(saita_ketsueki(lst1) == "A")
Console.log(saita_ketsueki(lst2) == "B")
Console.log(saita_ketsueki(lst3) == "A")
// 同点のときは A, O, B, AB の順に見つかったものが返されてしまう
Console.log(saita_ketsueki(lst4) == "A") 
Ex10_9.res
// 目的:lst1 と lst2 の長さが等しいかどうかを判定する
// equal_length : 'a list -> 'a list -> bool
let rec equal_length = (lst1, lst2) => switch (lst1, lst2) {
| (list{}, list{}) => true 
| (list{}, list{_, ..._}) => false 
| (list{_, ..._}, list{}) => false
| (list{_, ...rest1}, list{_, ...rest2}) => equal_length(rest1, rest2)
}

// テスト
Console.log(equal_length(list{}, list{}) == true)
Console.log(equal_length(list{}, list{1, 2}) == false)
Console.log(equal_length(list{1, 2}, list{}) == false)
Console.log(equal_length(list{1, 3}, list{2, 4}) == true)
Console.log(equal_length(list{"a", "b", "c", "d"}, list{1, 3}) == false)
Console.log(equal_length(list{"a", "b", "c", "d"}, list{1, 3, 2, 4}) == true)
Ex10_10.res
open Ex08_5 //ekimei_t の定義
open Ex09_9 //global_ekimei_list の定義

// 目的:ローマ字の駅名を漢字に直す
// romaji_to_kanji : string -> ekimei_t list -> string
let rec romaji_to_kanji = (r0, ekimei_list) => switch ekimei_list {
| list{} => ""
| list{{kanji: k, kana: _, romaji: r, shozoku: _}, ...rest} =>
    if r0 == r {k} else {romaji_to_kanji(r0, rest)}
}

// テスト
Console.log(romaji_to_kanji("myogadani", global_ekimei_list) == "茗荷谷")
Console.log(romaji_to_kanji("shibuya", global_ekimei_list) == "渋谷")
Console.log(romaji_to_kanji("otemachi", global_ekimei_list) == "大手町")
Ex10_11.res
open Ex08_7   // ekikan_t の定義
open Ex09_10  // global_ekikan_list の定義

// 目的:ふたつの駅の間の距離を求める
// get_ekikan_kyori : string -> string -> ekikan_t list -> float
let rec get_ekikan_kyori = (eki1, eki2, lst) => switch lst {
| list{} => Float.Constants.positiveInfinity
| list{{kiten: k, shuten: s, keiyu: _, kyori: r, jikan: _}, ...rest} =>
   if (eki1 == k && eki2 == s) || (eki1 == s && eki2 == k) {r}
   else {get_ekikan_kyori(eki1, eki2, rest)}
}

// テスト
if %raw(`require.main === module`) {
  Console.log(get_ekikan_kyori("茗荷谷", "新大塚", global_ekikan_list) == 1.2)
  Console.log(get_ekikan_kyori("茗荷谷", "池袋", global_ekikan_list) == Float.Constants.positiveInfinity)
  Console.log(get_ekikan_kyori("東京", "大手町", global_ekikan_list) == 0.6)
}
Ex10_12.res
open Ex08_5   // ekimei_t の定義
open Ex08_7   // ekikan_t の定義
open Ex09_9   // global_ekimei_list の定義
open Ex09_10  // global_ekikan_list の定義

// 目的:ローマ字の駅名を漢字に直す
// romaji_to_kanji : string -> ekimei_t list -> string
let rec romaji_to_kanji = (r0, ekimei_list) => switch (ekimei_list) {
| list{} => ""
| list{{kanji: k, kana: _, romaji: r, shozoku: _}, ...rest} =>
    if r0 == r {k} else {romaji_to_kanji(r0, rest)}
}

// 目的:ふたつの駅の間の距離を求める
// get_ekikan_kyori : string -> string -> ekikan_t list -> float
let rec get_ekikan_kyori = (eki1, eki2, lst) => switch lst {
| list{} => Float.Constants.positiveInfinity
| list{{kiten: k, shuten: s, keiyu: _, kyori: r, jikan: _}, ...rest} =>
   if (eki1 == k && eki2 == s) || (eki1 == s && eki2 == k) {r}
   else {get_ekikan_kyori(eki1, eki2, rest)}
}

// 目的:ふたつの駅の間の距離を文字列で表現する
let kyori_wo_hyoji = (romaji1, romaji2) => {
  let kanji1 = romaji_to_kanji(romaji1, global_ekimei_list)
  if kanji1 == "" {romaji1 ++ " という駅は存在しません"}
  else{
    let kanji2 = romaji_to_kanji(romaji2, global_ekimei_list)
    if kanji2 == "" {romaji2 ++ " という駅は存在しません"}
    else {
      let kyori = get_ekikan_kyori(kanji1, kanji2, global_ekikan_list)
	    if kyori == Float.Constants.positiveInfinity { 
	      kanji1 ++ "と" ++ kanji2 ++ "はつながっていません"
      } else {
        kanji1 ++ "から" ++ kanji2 ++ "までは " ++ Js.Float.toString(kyori) ++ " キロです"
      }
    }
  }
} 

// テスト
Console.log(kyori_wo_hyoji("myougadani", "shinotsuka") == "myougadani という駅は存在しません")
Console.log(kyori_wo_hyoji("myogadani", "shinotsuka") == "茗荷谷から新大塚までは 1.2 キロです")
Console.log(kyori_wo_hyoji("myogadani", "ikebukuro") == "茗荷谷と池袋はつながっていません")
Console.log(kyori_wo_hyoji("tokyo", "ootemachi") == "ootemachi という駅は存在しません")
Console.log(kyori_wo_hyoji("tokyo", "otemachi") == "東京から大手町までは 0.6 キロです")
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?