The and keyword is used either to exclude several let (the first example, I never use it for this, and why not), or for mutually recursive definitions of types, functions, modules ...
As you can see in your second example:
let rec debug stack env (r, ty) = ... | Tunresolved tyl -> o "intersect("; debugl stack env tyl; o ")" ... and debugl stack env x = ... | [x] -> debug stack env x ...
debug calls debugl and vice versa. Thus, and allows this.
[EDIT] I was worried about not giving an example, here is an example you will often see:
let rec is_even x = if x = 0 then true else is_odd (x - 1) and is_odd x = if x = 0 then false else is_even (x - 1)
(You can find this example here )
For mutually recursive types, itβs more difficult to find a configuration, but after this wikipedia page we will define trees and forests as follows
type 'a tree = Empty | Node of 'a * 'a forest and 'a forest = Nil | Cons of 'a tree * 'a forest
As an example, a forest consisting of an empty tree, a singleton tree labeled "a" and a tree of two nodes labeled "b" and "c" will then be represented as:
let f1 = Cons (Empty, (* Empty tree *) Cons (Node ('a', (* Singleton tree *) Nil), (* End of the first tree *) Cons (Node ('b', (* Tree composed by 'b'... *) Cons (Node ('c', (* and 'c' *) Nil), Nil) ), Nil (* End ot the second tree *) ) ) );;
And the size function (counting the number of nodes in the forest) will look like this:
let rec size_tree = function | Empty -> 0 | Node (_, f) -> 1 + size_forest f and size_forest = function | Nil -> 0 | Cons (t, f) -> size_tree t + size_forest f
And get