Jump to content

Variadic function: Difference between revisions

Add OCaml
(Add OCaml)
Line 2,056:
logObjects(@"Rosetta", @"Code", @"Is", @"Awesome!", nil);
logObjects(@4, @3, @"foo", nil);</lang>
 
=={{header|OCaml}}==
OCaml's strong type system makes writing variadic functions complex, as there is no <code>'a... -> 'b</code> type.
In general, writing a function that takes a list as argument is the best practice :
<lang ocaml>let rec print = function
| [] -> ()
| x :: xs -> print_endline x; print xs
 
(* Or better yet *)
let print = List.iter print_endline
 
let () =
print [];
print ["hello"; "world!"]</lang>
 
If you really need a true variadic function, there are a few ways to make it work.
The first is to specify the function's type with its first argument using a generalized algebraic data type (GADT) :
 
<lang ocaml>type 'a variadic =
| Z : unit variadic
| S : 'a variadic -> (string -> 'a) variadic
 
let rec print : type a. a variadic -> a = function
| Z -> ()
| S v -> fun x -> Format.printf "%s\n" x; print v
 
let () =
print Z; (* no arguments *)
print (S Z) "hello"; (* one argument *)
print (S (S (S Z))) "how" "are" "you" (* three arguments *)</lang>
 
You can even specify different types with more GADT constructors:
<lang ocaml>type 'a variadic =
| Z : unit variadic
| U : 'a variadic -> (unit -> 'a) variadic
| S : 'a variadic -> (string -> 'a) variadic
| I : 'a variadic -> (int -> 'a) variadic
| F : 'a variadic -> (float -> 'a) variadic
(* Printing of a general type, takes pretty printer as argument *)
| G : 'a variadic -> (('t -> unit) -> 't -> 'a) variadic
| L : 'a variadic -> (('t -> unit) -> 't list -> 'a) variadic
 
let rec print : type a. a variadic -> a = function
| Z -> ()
| U v -> fun () -> Format.printf "()\n"; print v
| S v -> fun x -> Format.printf "%s\n" x; print v
| I v -> fun x -> Format.printf "%d\n" x; print v
| F v -> fun x -> Format.printf "%f\n" x; print v
| G v -> fun pp x -> pp x; print v
| L v -> fun pp x -> List.iter pp x; print v
 
let () =
print (S (I (S Z))) "I am " 5 "Years old";
print (S (I (S (L (S Z))))) "I have " 3 " siblings aged " (print (I Z)) [1;3;7]</lang>
 
This is what the <code>Format.printf</code> functions do. The only difference is that the compiler constructs the GADT term from the given format string. This is why you can only call them with an explicit string argument, and not a variable of type string.
 
Another method uses continuation passing style (CPS) :
<lang ocaml>let print f = f ()
let arg value () cont = cont (Format.printf "%s\n" value)
let stop a = a
 
let () =
print stop;
print (arg "hello") (arg "there") stop;
 
(* use a prefix operator for arg *)
let (!) = arg
 
let () =
print !"hello" !"hi" !"its" !"me" stop</lang>
 
This isn't really a variadic function though, it's a hack that looks like one. The work is being done in the <code>arg</code> function, not <code>print</code>.
 
=={{header|Oforth}}==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.