練習問題 5.3
リストを集合とみなして、以下の集合演算をする関数を定義しなさい。
(*
* リストを集合とみなして、以下の集合演算をする関数を定義しなさい。
*)
(* 1: mem a s で、 a が s の要素かどうかを判定する関数 mem *)
let rec mem a s =
match s with
[] -> false
| v :: rest ->
if a = v
then true
else mem a rest;;
let test1 = mem 1 [2; 3; 5; -6; 1; 30] = true;;
let test2 = mem 4 [2; 3; 5; -6; 1; 30] = false;;
let s1 = [1; 2; -5; 20; 4];;
let s2 = [2; 3; -5; 34; 4];;
let cons a b = a :: b;;
let test99 = cons 1 [] = [1];;
(* let test98 = cons 1 2 = [1; 2];; *)
(* ========================================================= *)
(* 2: intersect s1 s2 で s1 と s2 の共通部分を返す関数 *)
let test97 = mem 3 [1; 2; 3; 4; 5; 6] = true;;
let test96 = mem 7 [1; 2; 3; 4; 5; 6] = false;;
(* 補助関数: リスト l の末尾に a を加える関数 *)
let rec add_last a l =
match l with
[] -> a :: []
| v :: rest ->
v :: (add_last a rest);;
let test95 = add_last 3 [2; 4; 6] = [2; 4; 6; 3];;
(* 2つのリスト s1 と s2 の共通部分を返す関数 *)
let intersect s1 s2 =
let rec intersect_in s1 s2 common =
match s1 with
[] -> common
| v :: rest ->
if (mem v s2)
then intersect_in rest s2 (add_last v common)
else intersect_in rest s2 common
in
intersect_in s1 s2 [];;
let test11 = intersect s1 s2 = [2; -5; 4];;
(* ================================================================ *)
(* 3: union s1 s2 で s1 と s2 の和を返す関数 union *)
let union s1 s2 =
let rec union_in s1 s2 ac =
match s1 with
[] -> ac @ s2
| v :: rest ->
if (mem v s2)
then union_in rest s2 ac
else union_in rest s2 (add_last v ac)
in
union_in s1 s2 [];;
let test21 = union s1 s2 = [1; 20; 2; 3; -5; 34; 4];;
(* ================================================================ *)
(* 4: diff s1 s2 で s1 と s2 の差を返す関数 diff *)
(* 和集合から共通集合を引くことで、差の集合がでる *)
let diff s1 s2 =
let inter_list = intersect s1 s2 in (* 共通部分 *)
let union_list = union s1 s2 in (* 和 *)
let rec diff_in un_list in_list ac =
match un_list with
[] -> ac
| v :: rest ->
if (mem v in_list)
then diff_in rest in_list ac
else diff_in rest in_list (add_last v ac)
in
diff_in union_list inter_list [];;
let test31 = diff s1 s2 = [1; 20; 3; 34];;