練習問題 5.2

次の関数を定義しなさい。

1. 正の整数 n から 1 までの整数の降順リストを生成する関数 downto1。

# let rec downto1 n = if n = 0 then [] else n :: downto1 (n-1);;
val downto1 : int -> int list = <fun>
# downto1 6;;
- : int list = [6; 5; 4; 3; 2; 1]

2. 与えられた正の整数のローマ数字表現を求める関数 roman。ただし,roman は単位となる 数とローマ数字表現の組を大きいものから並べたリストで表現した,ローマ数字の定義も引 数として受け取ることにする。

# let roman r n =
let rec iter_string n s = if n = 0 then "" else s ^ iter_string (n-1) s in
let roman' num rom =
let (n, s) = num in
let (rn, rs) = rom in
(n mod rn, s ^ iter_string (n / rn) rs)
in
snd (List.fold_left roman' (n, "") r)
;;
val roman : (int * string) list -> int -> string = <fun>
# roman [(1000,"M");(500,"D");(100,"C");(50,"L");(10,"X");(5,"V");(1,"I")] 1984;;
- : string = "MDCCCCLXXXIIII"

また,900,400,90,40,9,4 の表現を変えると

# roman [(1000,"M");(900,"CM");(500,"D");(400,"CD");(100,"C");(90,"XC");(50,"L");(4 0,"XL");(10,"X");(9,"IX");(5,"V");(4,"IV");(1,"I")] 1984;;
- : string = "MCMLXXXIV"

3. 与えられたリストのリストに対し,(内側のリストの)要素の総数を返す関数 nested_le ngth。

# let nested_length l = List.length (List.concat l);;
val nested_length : 'a list list -> int = <fun>
# nested_length [[1;2;3]; [4;5]; [6]; [7;8;9;10]];;
- : int = 10
# nested_length [[1;2;3]; [4;5]; []; [6;7;8;9]];;
- : int = 9

次の 4. を見て気がついた。もしかして List.concat は使っちゃだめだったのか?

# let nested_length l = List.fold_left (fun x y -> x + List.length y) 0 l;;
val nested_length : 'a list list -> int = <fun>
# nested_length [[1;2;3]; [4;5]; [6]; [7;8;9;10]];;
- : int = 10

4. 与えられたリストのリストに対し,内側のリストの要素を並べたリストを返す関数 concat。

# let concat l = List.fold_left (fun x y -> x @ y) [] l;;
val concat : '_a list list -> '_a list = <fun>
# concat [[1;2;3];[4;5];[6];[7;8;9;10]];;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]

もしかして List.fold_left も使わないのかな。なら再帰で。

# let rec concat' = function
[] -> []
| hd::tl -> hd @ concat' tl
;;
val concat' : 'a list list -> 'a list = <fun>
# concat' [[1;2;3]; [4;5]; [6]; [7;8;9;10]];;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]