I am reading a code snippet which confuses me a lot. I checked the OCaml Syntax for type, but cannot figure out which rule is applied.

So I have a type named state

type state =
| Decl
| Init

And I have a module named Symbol, which is used to store variable info, and its definition is

open Core
module T = struct
type t =
{ name : string [@compare.ignore] [@hash.ignore]
; id : int
}
[@@deriving compare, hash, sexp]
end
include T
include Comparable.Make (T)

Then there is a record table, storing the whole variable info and their values

type table =
{ vars : state Symbol.Map.t
; val : int
}

My question is

record constructor should be of form below, so state Symbol.Map.t should be a type. But state is a type, and Symbol.Map.t is another type. How can these two combined together without being a tuple?

Symbol.Map.t is not a type, but a type constructor, basically a mapping from types to types. state Symbol.Map.t means the type obtained by applying the constructor Symbol.Map.t to the type state as argument. In the page you linked, this corresponds to the rule typexpr ::= typexpr typeconstr.

The functor application Comparable.Make(T) returns a structure which includes the module Map within it (see core/comparable_intf.ml at 4b6635d206f7adcfac8324820d246299d6f572fe Âˇ janestreet/core Âˇ GitHub). This module Map defines a type constructor Map.t. As this structure is included in Symbol (include Comparable.Make(T)), the end result is that Symbol ends up with a type consturctor Symbol.Map.t.

In other words, 'a Symbol.Map.t is a generic type with a type parameter 'a, and state Symbol.Map.t is the concrete type of the map after âfilling inâ the type parameter with the state type.

In state Symbol.Map.t, state is to Symbol.Map.t the same as in int list, int is to list. list is a type constructor, int is a type, and int list is a type. A type constructor takes a type (or many) as argument and results in a type. It can be considered a function over types that that takes types as arguments and results in a type.

It makes sense for me to treat state Symbol.Map.t as a legal type obeying the OCaml syntax. But I still get some questions for type constructor.

How can I tell if a type is a generic type (type constructor) or a concrete type? Is type declared in a module without specifying a concrete type (like int, string) generic?

Also, I guess there are some rules for type constructors. It cannot take any type as its argument, right? In this example, why Symbol.Map.t can take state as its argument? I guess its due to [@@deriving compare, hash, sexp], but not quite sure.

I searched type constructor in Real World Ocaml and didnât find much results, how can I read more about it? Again, thank you for your helps!

By looking at the definition: type constructors have parameters, as in type 'a t or type ('a, 'b) t, while plain types do not have any parameters (eg type t). âPlainâ types can be considered zero arity type constructors.

Type constructors themselves can take any type as argument. In your example state could be replaced by any type whatsoever. The [@@deriving ...] annotations are there for the âkeyâ type, but for the âvalueâ type (state in your case) there are no restrictions at all.

Just to round out the explanation a bit more, in OCaml _ t is also valid syntax for generic types i.e. type constructors. It means ât takes a type parameter but I donât care about its name right nowâ.

And finally, OCaml also allows a limited form of type constraints on generic type parameters, so you can have something like type 'a t = 'a list constraint 'a = int, which as you can imagine, forces always only the int type as the type parameter here. Constraints are a more advanced technique so their use is more limited.