I've been reading through the list of OCaml warnings and am unsure what some of them mean (no examples are provided). Specifically, I'd like to understand:
Examples of code that trigger the following warnings (I think my interpretation of what each warning means is different from what it actually means because I am finding it difficult to produce cases that trigger the warnings that aren't outright language errors):
5. Partially applied function: expression whose result has function type and is ignored.
6. Label omitted in function application.
28. Wildcard pattern given as argument to a constant constructor.
59. Assignment to non-mutable value
What an "ancestor variable" and an "extension constructor" are:
36. Unused ancestor variable.
38. Unused extension constructor.
What these mean:
61. Unboxable type in primitive declaration
62. Type constraint on GADT type declaration
To complete the list:
A wild card pattern can be used as argument of an argument-less constructor
type t = A
let f x = match x with A _ -> 0
Warning 28: wildcard pattern given as argument to a constant constructor
This warning is raised when one names an inherited class without using it:
class c = object end
class d = object
inherit c as super
end
Warning 36: unused ancestor variable super.
An extension construction is a constructor added to an extensible sum type like exn
module M:sig end = struct
type exn += Unused
end
Warning 38: unused exception Unused
With recent versions of OCaml, it is possible to avoid boxing record with only one field or variant types with one constructor. This unboxing currently requires an annotation
type t = I of int [##unboxed]
However, the default representation may change in the future.
This change is transparent except for the FFI. Which means that external are paticularly brittle if they involve type without an annotation:
type t = I of int
external id: t -> t = "%identity"
Warning 61: This primitive declaration uses type t, which is unannotated and
unboxable. The representation of such types may change in future
versions. You should annotate the declaration of t with [##boxed]
or [##unboxed].
Type constraints does not apply on GADT arguments when defining a variant type. For instance, in
type 'a t =
| A: 'a -> float t
| B of 'a
constraint 'a = float
Warning 62: Type constraints do not apply to GADT cases of variant types.
The warning explains that B [] is an error, whereas A[] is fine.
This warning is an internal flambda warning, which warns that a value that flambda conjectured to be non-mutable was, in-fact, mutable. This warning should not be raised in normal circumstances.
Here's an example for warning 5:
# let f a b = a + b;;
val f : int -> int -> int = <fun>
# ignore (f 3);;
Warning 5: this function application is partial,
maybe some arguments are missing.
- : unit = ()
Warning 6 is disabled by default. If you enable it, it's easy to produce:
$ rlwrap ocaml -w +6
OCaml version 4.06.1
# let f ~a = a * 10;;
val f : a:int -> int = <fun>
# f 3;;
Warning 6: label a was omitted in the application of this function.
- : int = 30
The rest are beyond what I can figure out without looking at compiler sources. Maybe an expert or two will show up who can give examples for them.
Related
What this error means and how can i solve it? I am trying to generate types based on the CSS spec at styled-ppx and got stuck at this error that i dont know how to it fix neither what that means exactly.
I tried to get OCaml inference from the target file with dune using (ocamlc_flags -i :standard) because my suspect is that infered types and generated types are crashing since both are polymorphic variants, but had problems generating targets.
You can check the pull request with the problem being reproducible here
In your ppx code,
let mk_typ = (name, types) => {
let core_type = ptyp_variant(types, Closed, None);
it is unlikely that the meaning of types matches your expectation.
In this context, the list of type types represents an intersection (aka a conjunction) of types.
For instance, in
type 'a t = [< `A of int & float ] as 'a
the types list would contain the ast nodes for the type int and float.
(You can have a look at the latest version of OCaml manual https://ocaml.org/api/compilerlibref/Parsetree.html#TYPErow_field_desc to have more detailed description of those AST nodes.)
You probably meant to box the list of types in a product type
type t = [ `A of (int * float) ]
Indeed, polymorphic variant constructors always have arity one. Otherwise,
`A _ * _ would not be unifiable with `A of _.
Concerning your exact error message, the conjunctive type error that you are half-describing is likely related to the fact that conjunctive (like int & float) are only allowed as argument of polymorphic variant constructors in the upper bound of a polymorphic variant type.
In other words,
type 'a t = [< `A of int & float ] as 'a
is fine because we are on the right-hand side of <.
But both
type 'a t = [> `A of int & float ] as 'a
and
type t = [ `A of int & float ]
yields an error
Error: The present constructor A has a conjunctive type
because the conjunction of types appears in the lower bound of the type which lists the constructors that were explicitly present.
EDIT: Why are conjunctive types sometimes allowed?
Having conjunctive types makes it possible to use functions that have incoherent interpretation of some constructors.
For instance, I could have a function that works on either
`A of int or `B of float
let f = function
| `A n -> float_of_int n
| `B f -> f
and another function that expects both `A and `B to have a float argument
let g (`A f | `B f ) = f
If I try to apply f and g on the same argument
let h x = f x +. g x
I end up in a situation where h can be applied to `B 0. without trouble
let z = h (`B 0.)
but trying to use h on `A _ for any _ cannot work
let error = h (`A 0)
Error: This expression has type [> `A of int ]
but an expression was expected of type
[< `A of float & int | `B of float ]
Types for tag `A are incompatible
This is the kind of situation where conjunctive types arise: h has type [< `B of float | `A of int & float ] -> float. Moreover, we can wait to get a concrete argument of the form `A of x to check if the constructor argument x fit in the conjunction of types int & float. In this specific case, we know that there are no types that are both int and float, but more complex cases can happen, and delaying the check is a simple way to handle all cases.
Contrarily, when we have a concrete value of type [> `A of 'x ], there is no reason to delay this check. Thus it is not possible to construct a positive value that has a conjunctive type in OCaml. Consequently, it forbids the possibility to write types with conjunctive types in a positive position.
I was wondering why it is not possible to omit the auto keyword in some/all cases entirely, e.g.
int main()
{
[](auto x){}(10); // why this?
[](x){}(10); // and not this?
auto x = 10;
x = 10;
}
Is there a problem with ambiguity or something similiar? Or was it simple a design choice?
Consider this:
struct x {};
[](x){}(10);
Is that a lambda with an unnamed argument of type x (as per the current language spec) or is it am argument named x of deduced type (as per your suggestion)? Your suggested syntax is ambiguous with the pre-existing syntax of function parameter declarations.
x = 10;
This is even more problematic because it is indistinguishable from assignment. Someone writing this might be attempting to define a variable (your suggestion), but it can just as well be assignment of an existing variable depending on context. C++ has too much syntactical ambiguity (for the programmer) as it is. We should avoid adding more.
In other languages, we can have a function which takes no arguments. Can we have 0 argument function in ocaml?
Functions in OCaml have exactly one argument (ignoring complications due to optional arguments). So, you can't have a function with no arguments.
As #alfa64 says, you could consider a simple value as a function with no arguments. But it will always have the same value (which, in fact, makes it similar to a pure function).
If you want to write a function that doesn't actually require any arguments (one that has side effects, presumably), it is traditional to use () as its argument:
# let p () = Printf.printf "hello, world\n";;
val p : unit -> unit = <fun>
# p ();;
hello, world
- : unit = ()
#
In OCaml functions always have an arguments. Therefore, we might wonder how to translate the following say_hello C function in OCaml:
void
say_hello()
{
printf("Hello, world!\n");
}
There is a special type unit in OCaml which has only one value, written as (). While it might look odd and useless, it adds regularity to the language: a function not needing a specific argument can just take an argument of type unit, a function not returning a useful value usually returns a value of type unit. Here is how to translate the above say_hello function to OCaml:
# let say_hello () = print_endline "Hello, world!";;
val say_hello : unit -> unit = <fun>
Incidentally, template based meta-programming would be much easier in C++ if there were no type void but a similar unit type instead. It is quite common to treat separately functions having no arguments in template specialisations.
Object methods, while being similar to functions, do not require an argument.
# class example =
object
method a =
print_endline "This demonstrates a call to method a of class example"
end;;
class example : object method a : unit end
# let x = new example;;
val x : example = <obj>
# x # a ;;
This demonstrates a call to method a of class example
- : unit = ()
Instead of
let foo n = 55
You just
let foo = 55
And then call foo wherever.
Why can't I coerce record types in OCaml? Base types like int works fine.
Below is an example where I construct a base module M which I include in module A. M.t is type abbriviated in A. As long as M.t is int, I can do A.t' :> M.t. When I change it to {i : int}, the compiler says it's not a subtype. I'm guessing there is a very specific reason for this?
module M = struct
type t = {i : int}
let make () = {i = 10}
end
module A : sig
include module type of M
type t' = private t
val make : unit -> t'
end = struct
include M
type t' = t
end
In the toplevel:
(A.make() :> M.t);;
Error: Type A.t' is not a subtype of M.t
That's because A.t' has no relation to M.t, because include does not "preserve" equality, it just literally duplicates the module structure (or signature) and inlines it in place (as fresh types and values). So type M.t doesn't have any relation to A.t and therefore to A.t' (and different record types do not have structural subtyping defined like say objects or modules).
Obvious fix is type t' = private M.t.
UPDATE
It appears the above is not fully correct, because type t' = private M.t in signature and include M type t' = t in implemention do typecheck, so include M preserves the equality (otherwise it couldn't match the signature type t' = private M.t), unlike copypasting the contents of M in the place of include M. But this "obviously" doesn't hold for include module type of which creates fresh types..
In a.ml a record type t is defined and is also defined transparently
in a.mli, i.e. in d interface so that the type definition is available
to all other files.
a.ml also has a function, func, which returns a list of t.
Now in another file, b.ml i m calling func, now obviously ocaml
compiler wud nt be able to infer d type of objects stored in d list,
for compiler its just a list. so in b.ml, i hav something like dis,
let tlist = A.func in
let vart = List.hd tlist in
printf "%s\n" vart.name (*name is a field in record t*)
Now here i get a compiler error sayin "Unbound record field label
name" which makes sense as compiler can't infer d type of vart.
my first question: how do I explicitly provide d type of vart as t
here?
i tried doing "let vart:A.t = " but got the
same error.
I also tried creating another function to fetch the first element of d
list and mentioning return type as A.t, but then i got the "Unbound
value A.t". I did this:
let firstt = function
[] -> 0
| x :: _ -> A.t x ;;
The problem is compiler is unable to recognize A.t (a type) in b.ml
but is able to recognize function A.func. If I remove A.t from the
b.ml, i don'get any compiler errors.
The compiler is able to recognize A.t to designate type t from file a.ml.
On the other hand, t x where t is a type and x a variable is not a valid expression. This is the source of your problem. The compiler looks for the name t in the variables exported by a.ml. Since it cannot find this name used for a variable, it reports an error.
Now for what you were trying to do:
type annotations are not hints to the compiler in OCaml. It has an algorithm to infer the (most general, with some exceptions I am not entering into) type and then it checks that your annotation is at least a particularization of the most general type. The type annotation you provide will never (again, with some possible exceptions that do not concern you) make it change its mind.
To access in file b.ml the field f of a record r of type A.t, type r.A.f.
let tlist = A.func in
let vart = List.hd tlist in
printf "%s\n" vart.name (*name is a field in record t*)
Here tlist is a function, I suppose it is of type 'a -> A.t list, but you are applying an List.hd on that function when you write let vart = List.hd tlist.
You should provide the argument for your function to get the list of A.t for example let tlist = A.func (your_argument-s-_here), I guess this is the source of your error, the compiler is able to infer types between modules.