是否可以在不丢失 ocaml 中参数的多态类型的情况下设置函数的默认值

Is this possible to set a default value of a function without loosing the polymorphic type of an argument in ocaml

我有这个功能可以在文件中添加日志:

let log_datas f file (datas: 'a list) = 
  let oc = open_out file.file_name in 
    List.iter (fun x -> Printf.fprintf oc "%s" @@ f x) datas;
    close_out oc

let () = let f = string_of_int in  log_datas f {file_name="log"} [1;2]

哪个有效。

我试图让它默认接受字符串列表作为参数:

let log_datas ?(f:'a -> string = fun x -> x^"\n") file (datas: 'a list) = 
  let oc = open_out file.file_name in 
    List.iter (fun x -> Printf.fprintf oc "%s" @@ f x) datas;
    close_out oc

但是当我尝试

let () = let f = string_of_int in  log_datas ~f {file_name="log"} [1;2]

我遇到类型错误

23 | let () = let f = string_of_int in  log_datas ~f {file_name="log"} [1;2]
                                                   ^
Error: This expression has type int -> string
       but an expression was expected of type string -> string
       Type int is not compatible with type string

一个明显的解决方案是创建 2 个函数,一个不带 f 参数,一个带 f 参数。但我想知道,还有其他解决方法吗?

不,这是不可能的,您必须指定两个参数以保持多态性。基本上,您的示例可以提炼为

let log ?(to_string=string_of_int) data =
  print_endline (to_string data)

如果 OCaml 会保持它的多态性,那么将允许以下内容,

log "hello"

string_of_int "hello" 类型不正确。

所以你必须保留这两个参数,例如

let log to_string data = 
  print_endline (to_string data)

我还建议查看 Format 模块并定义您自己的多态函数,该函数使用格式规范来定义不同类型数据的写入方式,例如,

let log fmt = 
  Format.kasprintf print_endline fmt 

用我们自己的日志工具代替 print_endlinelog 函数可以用作 printf,例如,

log "%s %d" "hello" 42