Optional parameter at the end effects the label parameter before - ocaml

Why does let f ~x ?(y = 1) = x - y;; make the label for argument x become necessary? In other words, when I tried to evaluate f 3 ~y:2;;, I received this error:
Error: The function applied to this argument has type x:int -> int
This argument cannot be applied without label
What's the reason behind such design?

It is not necessary to label the argument x:
let g = f 0
works and returns a function g of type ?y:int -> int.
To understand this behaviour, it is best to remember that the generic rule is that
labels are mandatory when applying a function.
However, there is a specific rule for total application: if a function is applied to as many non-optional arguments as possible, then labels can be omitted.
A typical example would be
let f ~a ~b c d ~e f ~g = a + b + c + d + e + f + g
let x = f 1 2 3 4 5 6 7
Going back to your case, your function f takes at most one non-optional argument. It is thus considered as totally applied when applied to exactly one argument.
Another important point is that optional arguments are only send to the function once a subsequent positional argument has been sent. This explains why the variable g is still a function: no positional arguments were provided to f thus the optional argument ?y was never sent to f.
Applied to more complex example
let f ~a ?(b=0) c ~d e ~f ~g ?(h=0) = a + b + c + d +e + f + g + h
(* there are 8 arguments, 2 optional *)
(* g is applied to the full 6 non-optional arguments, thus total *)
let g = f 1 3 4 5 6 7
the type of g is ?h:int -> 0. Indeed, the application is total, thus all non-optional arguments have been provided. Then, the first optional argument ?b was followed by a positional argument. It was then provided to the function. However, the last optional argument ?h has not been yet triggered and is still here.
This behavior implies that optional argument are only useful if there is at least one positional argument after them, as advised by the compiler itself:
let f ~x ?(y=0) = x + y;;
Line 1, characters 11-14:
Warning 16: this optional argument cannot be erased.

Related

How is float_of_int -3 evaluated?

# float_of_int -3;;
Error: This expression has type int -> float
but an expression was expected of type int
I thought function application has the highest precedence, so float_of_int -3 is equal to float_of_int (-3). Why do I need to put the parentheses explicitly there to suppress the error?
Exactly because of this reason, that function application is having higher precedence than infix operators, you have to add parenthesis.
In other words, function application is greedy and it will consume all terms until it reaches an infix operator, e.g.,
f x y z + g p q r
is parsed as (f x y z) + (g p q r).
The same is with your example,
float_of_int - 3
is parsed as
(float_of_int) - (3)
Another option for you would be to use a special prefix operator ~-, e.g.,
float_of_int ~-1
which has higher precedence (binds tighter) than the function application.

Use variant from dependency

I have this code:
cnf.mli
type literal
type clause
type cnf
type l_diff
val l_compare: literal -> literal -> l_diff
cnf.ml (partial)
type l_diff = Same | Negation | Different
checker.ml (partial)
open Cnf
type solution = (literal * bool) list
let rec solve_literal sol l =
match sol with
| [] -> false
| (hl, b)::rs when (l_compare l hl) = Same -> b
| (hl, b)::rs when (l_compare l hl) = Negation -> not b
| _::rs -> solve_literal rs l
This works in utop using:
#mod_use "cnf.ml";;
#use "checker.ml";;
But if I try to compile checker I get the following error:
compile command:
ocamlbuild cnf.cma
ocamlbuild checker.cma
error:
+ /home/user/.opam/4.05.0/bin/ocamlc.opt -c -o checker.cmo checker.ml
File "checker.ml", line 7, characters 42-46:
Error: Unbound constructor Same
Hint: Did you mean Some?
Command exited with code 2.
Compilation unsuccessful after building 6 targets (2 cached) in 00:00:00.
Am I using a variant the wrong way, or using the compiler incorrectly?
Neither, you are using abstract types in signature in the wrong way. When you write in cnf.mli
type l_diff
this declares the type l_diff as an abstract type, in other words a black box whose content is hidden.
Contrarily, when using #mod_use "cnf.ml" the toplevel infers a signature by itself and makes all type declarations transparent:
type literal = …
type clause = …
type cnf = …
type l_diff = Same | Negation | Different
val l_compare: literal -> literal -> l_diff
(If you want to see the full inferred signature ocamlbuild cnf.inferred.mli should work.)
With this signature, the constructor of l_diff are visible and it becomes possible to construct directly or pattern match values of type l_diff.
More generally, your signature cnf.mli is far too restrictive:
With this signature, the only way to create a value of type l_diff is to call l_compare. However it would be then impossible to observe the content of the type. Similarly, with the interface cnf.mli that you provided, it is impossible to create a value of type literal.

Error when passing negative integer to a function in OCaml

If I define a function in OCaml, for example let f x = x + 1;; and then I try to call it passing a negative number
f -1;; it gives to me the following error
Error: This expression has type int -> int
but an expression was expected of type int
Why this error occurs?
Basically, it comes from the precedence of the parser. The compiler believes that f -1 means you want to subtract f by 1. It has been complained about for ages now.
Typing in f (-1) or f ~-1 will solve your problem (the later using the "explicitly unary minus").
UPDATE:
As stated in the OCaml manual:
Unary negation. You can also write - e instead of ~- e.
Basically, - can be used both as a binary operator 4 - 1 and a unary operator -1. But, as in your case, there can be confusion: f - 1 is "f minus one" and not "f applied to minus one". So the ~- operator was added to have a non-confusing unary minus as well.
Note that the spaces are not significant here, and that won't change because a lot of already existing code may contain operations without space.

caml-light last line not throwing warning

I'm playing with the difference between - as a unary operator and a binary operator in caml-light.
let a b =
print_int b;
print_newline();
;;
let c d e =
print_int d;
print_newline();
print_int e;
print_newline();
;;
a (3 - 4 ) ;
c (9 - 4 )
;;
I expect the code to either throw an error (because it gets confused about how many arguments a or c have) or to print:
-1
5
However, it compiles with no problems (compiler version below) and prints
-1
Can anyone tell me what happens with the last call?
Cobrakai$camlc -v
The Caml Light system, version 0.80
(standard library from /usr/local/lib/caml-light)
The Caml Light runtime system, version 0.80
The Caml Light compiler, version 0.80
The Caml Light linker, version 0.80
Cobrakai$
In ML, all functions take exactly one argument. A seemingly multi-parameter function is actually a function that takes one argument, and returns another function which takes the remaining arguments.
So let c d e = ... is actually syntactic sugar for let c = function d -> function e -> ...
And the type of c is int -> int -> unit, and -> is right-associative, so it is int -> (int -> unit). So you can see clearly that is a function which takes int and returns a function.
When you apply it to multiple arguments like c 1 2, function application is left-associative so it is actually (c 1) 2, so you can see that c 1 evaluates to a function which then is applied to 2.
So, when you give a function "too few arguments", the result is a function. This is a useful and common technique in ML called "partial application", which allows you a convenient way to "fix" the first few arguments of a function.
I am not sure how the Caml Light interpreter handles it when the expression you type evaluates to a function. But from what you're saying, it seems to not print anything.

Ocaml: Error - this expression has type x but is used with type x

This is my error:
Error: This expression has type nfa but is here used with type nfa
What could possibly be happening to cause this? I'm using emacs tuareg, and loading evaluating files one by one. Sometimes this happens, and other times it doesn't.
There's a good description of this in the ocaml tutorial. What's happened is you have shadowed a type definition with a new definition:
type nfa = int
let f (x: nfa) = x
type nfa = int
let g (x: nfa) = x
Restarting the top-level will clear out the old definitions.
Update:
Since OCaml 4.01.0 (released Sept. 2013) the general problem is the same, but the error message adds a number to the type definition, to make evident the types are internally different.
Full example from the old OCaml FAQ in the toplevel:
type counter = Counter of int;; (* define a type *)
type counter = Counter of int
# let x = Counter 1;; (* use the new type *)
val x : counter = Counter 1
type counter = Counter of int;; (* redefine the type, use it *)
type counter = Counter of int
# let incr_counter c = match c with Counter x -> Counter (x + 1);;
val incr_counter : counter -> counter = <fun>
# incr_counter x;; (* now mix old and new defs *)
Error: This expression has type counter/1029
but an expression was expected of type counter/1032
#