Why can't 'a and string unify? - sml

I'm trying to construct some flexible vector functions, similar to those for non-flexible vectors. I'm getting an error message that I don't understand:
> val jimmy = update(john,0,"mccoy");
Error-Type error in function application.
Function: update : 'a flexVector * int * 'a -> 'a flexVector
Argument: (john, 0, "mccoy") : string flexVector * int * string
Reason:
Can't unify 'a flexVector with string flexVector
(Different type constructors)
Found near update (john, 0, "mccoy")
Static Errors
How is this possible? For what I understand, the 'a datatype is non-specific and could therefore be string...?

Related

How the sequence type is defined in ocaml

type 'a node =
| Nil
| Cons of 'a * 'a t
and 'a t = unit -> 'a node
type 'a mappable = 'a t
What does 'a t = unit -> 'a node mean in a type declaration? I thought that in a type declaration in ocaml we can only do an enumeration or call a constructor.
thank you
unit -> 'a node is the type of a function that takes no argument and returns a 'a node (a node parameterized by 'a). Example :
let f () = Nil;;
type 'a t = unit -> 'a node makes a synonym of the above type which is used in the first type defined in your code.
let l = Cons (4, fun () -> Cons (3, fun () -> Nil));;
let Cons(_,ll) = l;; (* ok , just for example, it returns a warning due to incomplete pattern matching *)
ll ();; (* - : int node = Cons (3, <fun>) *)

OCaml variance (+'a, -'a) and invariance

After writing this piece of code
module type TS = sig
type +'a t
end
module T : TS = struct
type 'a t = {info : 'a list}
end
I realised I needed info to be mutable.
I wrote, then :
module type TS = sig
type +'a t
end
module T : TS = struct
type 'a t = {mutable info : 'a list}
end
But, surprise,
Type declarations do not match:
type 'a t = { mutable info : 'a list; }
is not included in
type +'a t
Their variances do not agree.
Oh, I remember hearing about variance. It was something about covariance and contravariance. I'm a brave person, I'll find about my problem alone!
I found these two interesting articles (here and here) and I understood!
I can write
module type TS = sig
type (-'a, +'b) t
end
module T : TS = struct
type ('a, 'b) t = 'a -> 'b
end
But then I wondered. How come that mutable datatypes are invariant and not just covariant?
I mean, I understand that an 'A list can be considered as a subtype of an ('A | 'B) list because my list can't change. Same thing for a function, if I have a function of type 'A | 'B -> 'C it can be considered as a subtype of a function of type 'A -> 'C | 'D because if my function can handle 'A and 'B's it can handle only 'A's and if I only return 'C's I can for sure expect 'C or 'D's (but I'll only get 'C's).
But for an array? If I have an 'A array I can't consider it as a an ('A | 'B) array because if I modify an element in the array putting a 'B then my array type is wrong because it truly is an ('A | 'B) array and not an 'A array anymore. But what about a ('A | 'B) array as an 'A array. Yes, it would be strange because my array can contain 'B but strangely I thought it was the same as a function. Maybe, in the end, I didn't understand everything but I wanted to put my thoughts on it here because it took me long to understand it.
TL;DR :
persistent : +'a
functions : -'a
mutable : invariant ('a) ? Why can't I force it to be -'a ?
I think that the easiest explanation is that a mutable value has two intrinsic operations: getter and setter, that are expressed using field access and field set syntaxes:
type 'a t = {mutable data : 'a}
let x = {data = 42}
(* getter *)
x.data
(* setter *)
x.data <- 56
Getter has a type 'a t -> 'a, where 'a type variable occurs on the right-hand side (so it imposes a covariance constraint), and the setter has type 'a t -> 'a -> unit where the type variable occurs to the left of the arrow, that imposes a contravariant constraint. So, we have a type that is both covariant and contravariant, that means that type variable 'a is invariant.
Your type t basically allows two operations: getting and setting. Informally, getting has type 'a t -> 'a list and setting has type 'a t -> 'a list -> unit. Combined, 'a occurs both in a positive and in a negative position.
[EDIT: The following is a (hopefully) clearer version of what I wrote in the first place. I consider it superior, so I deleted the previous version.]
I will try to make it more explicit. Suppose sub is a proper subtype of super and witness is some value of type super which is not a value of type sub. Now let f : sub -> unit be some function which fails on the value witness. Type safety is there to ensure that witness is never passed to f. I will show by example that type safety fails if one is allowed to either treat sub t as a subtype of super t, or the other way around.
let v_super = ({ info = [witness]; } : super t) in
let v_sub = ( v_super : sub t ) in (* Suppose this was allowed. *)
List.map f v_sub.info (* Equivalent to f witness. Woops. *)
So treating super t as a subtype of sub t cannot be allowed. This shows covariance, which you already knew. Now for contravariance.
let v_sub = ({ info = []; } : sub t) in
let v_super = ( v_sub : super t ) in (* Suppose this was allowed. *)
v_super.info <- [witness];
(* As v_sub and v_super are the same thing,
we have v_sub.info=[witness] once more. *)
List.map f v_sub.info (* Woops again. *)
So, treating sub t as a subtype of super t cannot be allowed either, showing contravariance. Together, 'a t is invariant.

Why can't I add type constraints when implementing a module type?

I was trying (just out of interest) to do this:
module type CAT = sig
type ('a, 'b) t
val id : ('a, 'a) t
val (#) : ('b, 'c) t -> ('a, 'b) t -> ('a, 'c) t
end
module Lst = struct
type ('a, 'b) t = 'a list constraint 'a = 'b
let id = []
let (#) = (#)
end
module L : CAT = Lst (* (error) *)
But I get:
Type declarations do not match:
type ('b, 'a) t = 'b list constraint 'a = 'b
is not included in
type ('a, 'b) t
Why isn't this safe? Everything that can see the concrete type can also see the constraint, so I don't think you could make something with a wrong type (e.g. call # with a (string, int) t argument).
Update: to those saying that my module doesn't implement the signature because it requires the types to be the same, consider that the following (which just wraps the lists in a List variant) is accepted despite having the same behaviour:
module Lst = struct
type ('a, 'b) t =
List : 'a list -> ('a, 'a) t
let id = List []
let (#) (type a) (type b) (type c) (a:(b, c) t) (b:(a, b) t) : (a, c) t =
match a, b with
| List a, List b -> List (a # b)
end
The example can be reduced to the type definition alone:
module type S =
sig
type ('a, 'b) t
end
module M =
struct
type ('a, 'b) t = 'a list constraint 'a = 'b
end
As Jeffrey already pointed out, M is not of type S, because it allows fewer applications of t: according to signature S, the type (int, string) t would be perfectly legal (it is well-formed), but M does not allow this type ((int, string) M.t is not a legal type, because it violates the explicit constraint).
All that is completely independent from the question whether the type is actually inhabited, i.e., whether you can construct values of the type. In your second example, the module makes the respective type well-formed, though it is uninhabited. Uninhabited types are legal, however, and sometimes even useful (see e.g. the concept of phantom types).
The type signature CAT is more general than the type of the Lst module. You need to put the type constraint on the abstract type too, i.e. type ('a, 'b) t constraint 'a = 'b.
This gives us the following:
module type CAT = sig
type ('a, 'b) t constraint 'a = 'b
val id : ('a, 'a) t
val (#) : ('b, 'c) t -> ('a, 'b) t -> ('a, 'c) t
end
which is printed as follows by the toplevel, showing a single type variable in the signature of (#):
module type CAT =
sig
type ('b, 'a) t constraint 'a = 'b
val id : ('a, 'a) t
val ( # ) : ('c, 'c) t -> ('c, 'c) t -> ('c, 'c) t
end
Error messages of the form "type x is not included in type y" refer to types or module types as specifications of sets of possible values, hence the use of the term "included".
In the case of a module implementation (Lst), we have a module type for it. Applying a signature (module type CAT) to a module is only allowed if that signature is as specialized (equal set) or more specialized (strict subset) than the original signature of the module.
One can write module X : sig val f : unit -> unit end = struct let f x = x end
but not module X : sig val f : 'a -> 'a end = struct let f () = () end. The latter gives the following error:
Error: Signature mismatch:
Modules do not match:
sig val f : unit -> unit end
is not included in
sig val f : 'a -> 'a end
Values do not match:
val f : unit -> unit
is not included in
val f : 'a -> 'a
This is different than placing type constraints on certain expressions, in which case the constraint is a mask to be applied (a set to intersect with) rather than a subset. For example it is fine to write let f : unit -> 'a = fun x -> x even though f's signature ends up being unit -> unit, a strict subset - or subtype - of unit -> 'a.
Your Lst module doesn't seem to me to have the type CAT. CAT allows the two types 'a and 'b to be independent. The Lst module requires them to be the same. If the L module were of type CAT then it should allow me to make something of type (string, int) t but it doesn't.
The error message is a little confusing, at least to me.

Ocaml: function with no parameters to return generic pair in tuple list

I wanted to write a function with following signature to use in association dictionary
empty: unit -> ('a * 'b) list
I am assuming it will be something like
let empty () = ...
But how can I create a list with specific type?
If your function returns an empty list it will have the type you want:
# let empty () : ('a * 'b) list = [];;
val empty : unit -> ('a * 'b) list = <fun>
The natural type of this function is unit -> 'a list, but OCaml will let you "slim down" the type into a more specific one.
You can specify a type for any expression in the form ( expr : type ):
# let empty () = ([] : ('a * 'b) list);;
val empty : unit -> ('a * 'b) list = <fun>
Of course, the type has to be correct (must unify with the inferred type of the expression).
Update
As newacct points out, you could use a value rather than a function.
# let (empty : ('a * 'b) list) = [];;
val empty : ('a * 'b) list = []
This is a common way to define an empty pure structure (as in the Map module).

GADT definition

This is just a test so I'm not much concerned, but I have these definitions:
type z
type _ s
type (_, _, _) balance =
| Less : (*∀'a.*) ('a, 'a s, 'a s) balance
| Same : (*∀'b.*) ('b, 'b, 'b) balance
| More : (*∀'a.*) ('a s, 'a, 'a s) balance
type _ aVL =
| Leaf : z aVL
| Node : (*∀'a, 'b, 'c.*)('a, 'b, 'c) balance * 'a aVL * int * 'b aVL ->
('c s) aVL
and I get the error for "type _ aVL =":
Error: In this definition, a type variable cannot be deduced
from the type parameters.
What to do?
H/T to Gabriel Scherer for answering at caml-list.
Don't use this kind of abstract type definition. Use instead (and export) concrete definitions (even if you don't use their constructors for anything)
type 'a s = S of 'a
(or just type 'a s = S)
They have "better" injectivity properties. We've mentioned in on the mailing-list a couple of time, and it's also the "easy take-away lesson" from Jacques Garrigue talk at the OCaml workshop in September.
Shame on me for not googling for the problem. Here the exact problem is addressed: GADTs : a type variable cannot be deduced