Type definition using modules

I found something similar to this piece of code:


module Pairs = struct
          type 'a pair = 'a * 'a
          let pair (a,b) = (a,b)
          let first (a,_) = a
          let second (_,b) = b
end;;

type 'a quad = 'a Pairs.pair Pairs.pair;;

I am confused about the last line, and the fact that Pairs.pair is both a function and a type.
Yes, I know that values and types have different namespaces. I still don’t get what the right hand side of the line does.

I am a beginner, so I am used to type definitions like type 'a some_type = 'a * 'a , where the star “*” is used to make a larger tuple. If I do in utop type 'a quad = 'a Pairs.pair * 'a Pairs.pair;; , the code compiles, but I guess it’s doing a pair of two pairs, and I believe the intention of the quad data structure above was to implement a 4-tuple (not a tuple of tuples).

The last paragraph may have complicated the question, which is simply “what does the last line mean?”

The last line is a type alias:

type 'a quad = 'a Pairs.pair Pairs.pair;;

It says, anywhere you see 'a quad, you can replace it with 'a Pairs.pair Pairs.pair. The fact that Pairs.pair is a function is irrelevant.

Another type alias could be:

type 'a arbitrary_name = 'a list

Usually, people create type aliases to simplify complicated type expressions and make their code more concise.

For example, to annotate an argument of a function as taking a nested pair:

let my_fun (x: 'a Pairs.pair Pairs.pair) = ...

we can write the following instead:

let my_fun (x: 'a quad) = ...

which is more concise and encodes more of the desired semantics of the author.

First of all thank you for your answer. I deepened my insight.

I still don’t feel confident with this particular line of code.
To illustrate, what you provided as an example (type 'a arbitrary_name = 'a list ) is very straightforward and I like it: whenever there is a list, I can consider as an arbitrary_name object. This is easy for me to visualise.

I’m still having a hard time to picture the right hand side of:

type 'a quad = 'a Pairs.pair Pairs.pair;;

Questions:

  1. Is the first Pairs.pair the function (let pair (a,b) = (a,b) ), or the type (type 'a pair = 'a * 'a)?
  2. Is the second Pairs.pair the function (let pair (a,b) = (a,b) ), or the type (type 'a pair = 'a * 'a)?
  3. In the toy-examples I’ve seen thus far, when a type is defined the right hand side of the definition contains only types (like type 'a some_type = 'a * 'a ). Values and types have different namespaces. Is it anyway possible to include values (like functions) in the type definition?

Both occurrences of Pair.pair refer to the type.

In isolation, the type defined by the last line is equivalent to the following:

type 'a pair = 'a * 'a
type 'a quad = 'a pair pair

I think maybe you’re getting confused by the associativity of types?

'a pair pair

is equivalent to

('a pair) pair

Similarly, if I wanted a type to represent list of lists, I would use 'a list list (equivalent to ('a list) list).

AFAIK, values can’t be included in type definitions.

Thank you for your patience.

I think I am finally getting it. Just one last (dumb) question.

Consider ('a list) list) . If both are types, in other words not the case where the first is a function/constructor and the second a type argument, how does OCaml establish the relation between the 2: a list of lists?

To be more precise list is a type constructor: it is a function from types to types.

In other words, 'a list is applying the type constructor list to 'a, resulting in the type of list of elements of type 'a. And 'a list list is applying the type constructor list to the type 'a list returning the type of list of lists of elements of type 'a.

2 Likes