在 OCaml 中组合用于 Hashtbl 和 Map.S 的字符串表示的函数

Combining functions for string representation of Hashtbl and Map.S in OCaml

简而言之,我正在尝试制作通用函子或函数来为 HashtblMap.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 的元素转换为 stringlist 和 returns liststring 表示.

map_ds_fold_func_generator的目的是抽象用来折叠HashtblMap.S结构的函数。 string_of_keystring_of_val 分别是用于将映射的键值对中的键和值转换为 string 的函数。然后 returns 可以用来将键值对转换为字符串的函数,并将其添加到折叠函数的累加列表中。

string_of_hashtbl 用于将 Hashtbl.t 转换为 stringstring_of_keystring_of_val同上意思

StringOfMap 模块中的

string_of_map 用于将 Map.S.t 转换为 stringstring_of_keystring_of_val同上意思

string_of_hashtblstring_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)