在 OCaml 中组合用于 Hashtbl 和 Map.S 的字符串表示的函数
Combining functions for string representation of Hashtbl and Map.S in OCaml
简而言之,我正在尝试制作通用函子或函数来为 Hashtbl
和 Map.S
模块类型创建字符串形式。
我个人实现了这样的功能,但是还是有很多冗余代码。
这是我目前拥有的:
let string_of_list (string_of_el: 'a -> string) (lst: 'a list): string =
List.map string_of_el lst |> String.concat "; " |> Printf.sprintf "[%s]"
let map_ds_fold_func_generator (string_of_key: 'a -> string) (string_of_val: 'b -> string): 'a -> 'b -> string list -> string list =
let map_fold_func (key: 'a) (value: 'b) (accum: string list): string list =
(Printf.sprintf "(%s, %s)" (string_of_key key) (string_of_val value))::accum
in map_fold_func
let string_of_hashtbl (string_of_key: 'a -> string) (string_of_val: 'b -> string) (tbl: ('a, 'b) Hashtbl.t): string =
string_of_list Fun.id (Hashtbl.fold (map_ds_fold_func_generator string_of_key string_of_val) tbl [])
module StringOfMap (M: Map.S) = struct
let string_of_map string_of_key string_of_val map =
string_of_list Fun.id (M.fold (map_ds_fold_func_generator string_of_key string_of_val) map [])
end
函数说明:
string_of_list
不言自明。它接受一个函数,将 list
的元素转换为 string
和 list
和 returns list
的 string
表示.
map_ds_fold_func_generator
的目的是抽象用来折叠Hashtbl
或Map.S
结构的函数。 string_of_key
和 string_of_val
分别是用于将映射的键值对中的键和值转换为 string
的函数。然后 returns 可以用来将键值对转换为字符串的函数,并将其添加到折叠函数的累加列表中。
string_of_hashtbl
用于将 Hashtbl.t
转换为 string
。 string_of_key
和string_of_val
同上意思
StringOfMap
模块中的 string_of_map
用于将 Map.S.t
转换为 string
。 string_of_key
和string_of_val
同上意思
string_of_hashtbl
和string_of_map
功能布局相同:
let string_of_map_ds string_of_key string_of_val ds =
string_of_list Fun.id (DS.fold (map_ds_fold_func_generator string_of_key string_of_val) ds [])
然而,主要是因为 t
的定义不同,我正在努力寻找一种方法来减少非常相似的功能布局中的冗余。
下面使用Seq
模块来做。基本上,您只需要一个将序列转换为列表字符串的函数,然后使用适当的数据结构调用它以进行序列转换(它本身作为参数传递给更高级别的函数):
let string_of_list (string_of_el: 'a -> string) (lst: 'a list): string =
List.map string_of_el lst |> String.concat "; " |> Printf.sprintf "[%s]"
let pair_to_string (string_of_fst: 'a -> string)
(string_of_snd: 'b -> string) ((fst:'a), (snd:'b)): string =
let s1 = string_of_fst fst
and s2 = string_of_snd snd in
Printf.sprintf "(%s, %s)" s1 s2
let string_of_seq (string_of_fst: 'a -> string)
(string_of_snd: 'b -> string) (s: ('a * 'b) Seq.t): string =
List.of_seq s |> string_of_list (pair_to_string string_of_fst string_of_snd)
let string_of_ds (string_of_key: 'a -> string)
(string_of_val: 'b -> string)
(to_seq: 'c -> ('a * 'b) Seq.t) (ds:'c): string =
to_seq ds |> string_of_seq string_of_key string_of_val
let string_of_hashtbl (string_of_key: 'a -> string)
(string_of_val: 'b -> string) (tbl: ('a, 'b) Hashtbl.t): string =
string_of_ds string_of_key string_of_val Hashtbl.to_seq tbl
module StringOfMap (M: Map.S) = struct
type key = M.key
type 'a t = 'a M.t
let string_of_map (string_of_key: key -> string)
(string_of_val: 'a -> string) (map: 'a t): string =
string_of_ds string_of_key string_of_val M.to_seq map
end
module StringMap = Map.Make(String)
let _ =
let module PrintableMap = StringOfMap(StringMap) in
let example = [ ("dog", 1); ("cat", 2); ("chicken", 3); ("rat", 4);
("goat", 5)] in
let htable = List.to_seq example |> Hashtbl.of_seq
and smap = List.to_seq example |> StringMap.of_seq in
print_endline (string_of_hashtbl Fun.id Int.to_string htable);
print_endline (PrintableMap.string_of_map Fun.id Int.to_string smap)
或者,您可以使用看起来更像您的版本的东西,方法是将几乎重复的代码提取到它自己的函数中,该函数将适当模块的折叠例程作为参数,就像上面对 to_seq
函数:
let string_of_list (string_of_el: 'a -> string) (lst: 'a list): string =
List.map string_of_el lst |> String.concat "; " |> Printf.sprintf "[%s]"
let map_ds_fold_func_generator (string_of_key: 'a -> string)
(string_of_val: 'b -> string): 'a -> 'b -> string list -> string list =
fun key value accum -> (Printf.sprintf "(%s, %s)" (string_of_key key)
(string_of_val value))::accum
(* This is why I prefer type inference to explicit typing *)
let string_of_ds (string_of_key: 'a -> string)
(string_of_val: 'b -> string)
(fold_fn: ('a -> 'b -> string list -> string list)
-> 'c -> string list -> string list)
(ds: 'c): string =
string_of_list Fun.id
(fold_fn (map_ds_fold_func_generator string_of_key string_of_val) ds [])
let string_of_hashtbl (string_of_key: 'a -> string)
(string_of_val: 'b -> string) (tbl: ('a, 'b) Hashtbl.t): string =
string_of_ds string_of_key string_of_val Hashtbl.fold tbl
module StringOfMap (M: Map.S) = struct
type key = M.key
type 'a t = 'a M.t
let string_of_map (string_of_key: key -> string)
(string_of_val: 'a -> string) (map: 'a t): string =
string_of_ds string_of_key string_of_val M.fold map
end
module StringMap = Map.Make(String)
let _ =
let module PrintableMap = StringOfMap(StringMap) in
let example = [ ("dog", 1); ("cat", 2); ("chicken", 3); ("rat", 4);
("goat", 5)] in
let htable = List.to_seq example |> Hashtbl.of_seq
and smap = List.to_seq example |> StringMap.of_seq in
print_endline (string_of_hashtbl Fun.id Int.to_string htable);
print_endline (PrintableMap.string_of_map Fun.id Int.to_string smap)
简而言之,我正在尝试制作通用函子或函数来为 Hashtbl
和 Map.S
模块类型创建字符串形式。
我个人实现了这样的功能,但是还是有很多冗余代码。
这是我目前拥有的:
let string_of_list (string_of_el: 'a -> string) (lst: 'a list): string =
List.map string_of_el lst |> String.concat "; " |> Printf.sprintf "[%s]"
let map_ds_fold_func_generator (string_of_key: 'a -> string) (string_of_val: 'b -> string): 'a -> 'b -> string list -> string list =
let map_fold_func (key: 'a) (value: 'b) (accum: string list): string list =
(Printf.sprintf "(%s, %s)" (string_of_key key) (string_of_val value))::accum
in map_fold_func
let string_of_hashtbl (string_of_key: 'a -> string) (string_of_val: 'b -> string) (tbl: ('a, 'b) Hashtbl.t): string =
string_of_list Fun.id (Hashtbl.fold (map_ds_fold_func_generator string_of_key string_of_val) tbl [])
module StringOfMap (M: Map.S) = struct
let string_of_map string_of_key string_of_val map =
string_of_list Fun.id (M.fold (map_ds_fold_func_generator string_of_key string_of_val) map [])
end
函数说明:
string_of_list
不言自明。它接受一个函数,将 list
的元素转换为 string
和 list
和 returns list
的 string
表示.
map_ds_fold_func_generator
的目的是抽象用来折叠Hashtbl
或Map.S
结构的函数。 string_of_key
和 string_of_val
分别是用于将映射的键值对中的键和值转换为 string
的函数。然后 returns 可以用来将键值对转换为字符串的函数,并将其添加到折叠函数的累加列表中。
string_of_hashtbl
用于将 Hashtbl.t
转换为 string
。 string_of_key
和string_of_val
同上意思
StringOfMap
模块中的 string_of_map
用于将 Map.S.t
转换为 string
。 string_of_key
和string_of_val
同上意思
string_of_hashtbl
和string_of_map
功能布局相同:
let string_of_map_ds string_of_key string_of_val ds =
string_of_list Fun.id (DS.fold (map_ds_fold_func_generator string_of_key string_of_val) ds [])
然而,主要是因为 t
的定义不同,我正在努力寻找一种方法来减少非常相似的功能布局中的冗余。
下面使用Seq
模块来做。基本上,您只需要一个将序列转换为列表字符串的函数,然后使用适当的数据结构调用它以进行序列转换(它本身作为参数传递给更高级别的函数):
let string_of_list (string_of_el: 'a -> string) (lst: 'a list): string =
List.map string_of_el lst |> String.concat "; " |> Printf.sprintf "[%s]"
let pair_to_string (string_of_fst: 'a -> string)
(string_of_snd: 'b -> string) ((fst:'a), (snd:'b)): string =
let s1 = string_of_fst fst
and s2 = string_of_snd snd in
Printf.sprintf "(%s, %s)" s1 s2
let string_of_seq (string_of_fst: 'a -> string)
(string_of_snd: 'b -> string) (s: ('a * 'b) Seq.t): string =
List.of_seq s |> string_of_list (pair_to_string string_of_fst string_of_snd)
let string_of_ds (string_of_key: 'a -> string)
(string_of_val: 'b -> string)
(to_seq: 'c -> ('a * 'b) Seq.t) (ds:'c): string =
to_seq ds |> string_of_seq string_of_key string_of_val
let string_of_hashtbl (string_of_key: 'a -> string)
(string_of_val: 'b -> string) (tbl: ('a, 'b) Hashtbl.t): string =
string_of_ds string_of_key string_of_val Hashtbl.to_seq tbl
module StringOfMap (M: Map.S) = struct
type key = M.key
type 'a t = 'a M.t
let string_of_map (string_of_key: key -> string)
(string_of_val: 'a -> string) (map: 'a t): string =
string_of_ds string_of_key string_of_val M.to_seq map
end
module StringMap = Map.Make(String)
let _ =
let module PrintableMap = StringOfMap(StringMap) in
let example = [ ("dog", 1); ("cat", 2); ("chicken", 3); ("rat", 4);
("goat", 5)] in
let htable = List.to_seq example |> Hashtbl.of_seq
and smap = List.to_seq example |> StringMap.of_seq in
print_endline (string_of_hashtbl Fun.id Int.to_string htable);
print_endline (PrintableMap.string_of_map Fun.id Int.to_string smap)
或者,您可以使用看起来更像您的版本的东西,方法是将几乎重复的代码提取到它自己的函数中,该函数将适当模块的折叠例程作为参数,就像上面对 to_seq
函数:
let string_of_list (string_of_el: 'a -> string) (lst: 'a list): string =
List.map string_of_el lst |> String.concat "; " |> Printf.sprintf "[%s]"
let map_ds_fold_func_generator (string_of_key: 'a -> string)
(string_of_val: 'b -> string): 'a -> 'b -> string list -> string list =
fun key value accum -> (Printf.sprintf "(%s, %s)" (string_of_key key)
(string_of_val value))::accum
(* This is why I prefer type inference to explicit typing *)
let string_of_ds (string_of_key: 'a -> string)
(string_of_val: 'b -> string)
(fold_fn: ('a -> 'b -> string list -> string list)
-> 'c -> string list -> string list)
(ds: 'c): string =
string_of_list Fun.id
(fold_fn (map_ds_fold_func_generator string_of_key string_of_val) ds [])
let string_of_hashtbl (string_of_key: 'a -> string)
(string_of_val: 'b -> string) (tbl: ('a, 'b) Hashtbl.t): string =
string_of_ds string_of_key string_of_val Hashtbl.fold tbl
module StringOfMap (M: Map.S) = struct
type key = M.key
type 'a t = 'a M.t
let string_of_map (string_of_key: key -> string)
(string_of_val: 'a -> string) (map: 'a t): string =
string_of_ds string_of_key string_of_val M.fold map
end
module StringMap = Map.Make(String)
let _ =
let module PrintableMap = StringOfMap(StringMap) in
let example = [ ("dog", 1); ("cat", 2); ("chicken", 3); ("rat", 4);
("goat", 5)] in
let htable = List.to_seq example |> Hashtbl.of_seq
and smap = List.to_seq example |> StringMap.of_seq in
print_endline (string_of_hashtbl Fun.id Int.to_string htable);
print_endline (PrintableMap.string_of_map Fun.id Int.to_string smap)