Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OCaml Optional Argument

How can I write a function in OCaml in which one or more argument are optional?

let foo x y z = if(x+y > z) then true else false;;

If foo do not receive the z argument it uses 0 as z.

foo 3 3 2 -> true
foo 3 3 10 -> false
foo 2 1 -> true

Is there any OCaml feature to achieve this?

like image 729
user3645997 Avatar asked May 16 '14 19:05

user3645997


Video Answer


2 Answers

OCaml has optional arguments, but it's quite a bit trickier than you would expect because OCaml functions fundamentally have exactly one argument. In your case, foo is a function that expects an int and returns a function.

If you leave off trailing arguments, normally this means that you're interested in the function that will be returned; this is sometimes called partial application.

The result is that trailing optional arguments (as you are asking for) do not work.

Optional arguments are always associated with a name, which is used to tell whether the argument is being supplied or not.

If you make z the first argument of your function rather than the last, you can get something like the following:

# let foo ?(z = 0) x y = x + y > z;;
val foo : ?z:int -> int -> int -> bool = <fun>
# foo 3 3 ~z: 2;;
- : bool = true
# foo 3 3 ~z: 10;;
- : bool = false
# foo 2 1;;
- : bool = true

In general I'd say that optional (and named) arguments in OCaml don't solve the same problems as in some other languages.

I personally never define functions with optional arguments; so, there may be better ways to achieve what you're asking for.

like image 100
Jeffrey Scofield Avatar answered Oct 10 '22 01:10

Jeffrey Scofield


OCaml doesn't have optional arguments like you'd find in Java or C#. Since functions can be partially applied, optional arguments can make it hard to tell when you're done passing arguments and would like the function to be evaluated. However, OCaml does have labeled arguments with default values, which can be used to the same effect.

The usual caveats of labeled arguments apply. Note that labeled arguments can't appear at the end of the argument list since the function is evaluated as soon as it has everything it needs:

let foo x y ?z_name:(z=0) = (x + y) > z;;
Characters 12-39:
  let foo x y ?z_name:(z=0) = (x + y) > z;;
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Warning 16: this optional argument cannot be erased.
val foo : int -> int -> ?z_name:int -> bool = <fun>

Other parts of the argument list are fine:

# let foo ?z:(z=0) x y = (x + y) > z;;
val foo : ?z:int -> int -> int -> bool = <fun>
# foo 1 1;;
- : bool = true
# foo (-1) (-1);;
- : bool = false
# foo ~z:(-42) (-1) (-1);;
- : bool = true

In the same fashion as above, you lose the ability to supply the optional argument once you 'move past' it in the argument list:

# foo 1;;
- : int -> bool = <fun>
like image 19
Gordon Gustafson Avatar answered Oct 10 '22 01:10

Gordon Gustafson