I have this function to add logs in a file :
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]
Which works.
I tried to make it by default accepting string list as argument :
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
but when I try
let () = let f = string_of_int in log_datas ~f {file_name="log"} [1;2]
I get a type error
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
An obvious solution would be to make 2 function, one with no f
argument and one with a f
argument. But I was wondering, is there any other workaround possible ?
CodePudding user response:
No, it is not possible, you have to specify both parameters to keep it polymorphic. Basically, your example could be distilled to,
let log ?(to_string=string_of_int) data =
print_endline (to_string data)
If OCaml would keep it polymorphic then the following would be allowed,
log "hello"
and string_of_int "hello"
is not well-typed.
So you have to keep both parameters required, e.g.,
let log to_string data =
print_endline (to_string data)
I would also suggest looking into the Format
module and defining your own polymorphic function that uses format specification to define how data of different types are written, e.g.,
let log fmt =
Format.kasprintf print_endline fmt
Substitute print_endline
with our own logging facility. The log
function could be used as printf
, e.g.,
log "%s %d" "hello" 42