Variadic function: Difference between revisions

Content added Content deleted
(Add OCaml)
Line 2,056: Line 2,056:
logObjects(@"Rosetta", @"Code", @"Is", @"Awesome!", nil);
logObjects(@"Rosetta", @"Code", @"Is", @"Awesome!", nil);
logObjects(@4, @3, @"foo", nil);</lang>
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}}==
=={{header|Oforth}}==