Main idea of splay (from README):
The splay operation is not equivalent to rotating an node all the
way to the root using single rotations. Instead, double rotations
(together with single rotation) are used here. Most of the time
the node will be moved to the root by double rotations. Only when
the depth of the accessed node is odd (if we define the depth of
the root as 0), a single rotation at the end is needed.
A path consisting of the nodes and directions from the root to the
node being accessed (thus has the depth information) is useful to
the splay operation. However, we can do splay without explicitly
constructing a path, since the path information is already
contained in the recursion of splay. The only reason that we need
a path is we don't know how to recursively run splay before we
know the depth of the node.
OK, if moving the node to the root is not insisted, we may do the
job in one recursion. In splay_set.ml, a function that moves the
accessed node to the root OR the left/right child of the root,
which is named splay2, is used. It also provides the direction
(Left or Right) information, or strictly, the position of the node
asked after splay2 (Root/Left/Right), to its caller.
Then the recursion is easy. First, splay2 checks whether the node
asked is already in its root, or if the tree is too simple (such
as a Leaf). If so, then return the original tree, and the position
information 'Root'. Otherwise, it calls itself to splay2 its left
or right subtree. If the last call returns that the node is in the
root (of the left/right subtree), nothing need to do and just
return the position of the node (Left/Right). If the node is also
in the left or right subtree of the subtree, then a double rotation
is carried out, and 'Root' is returned.
Splay2 uses only the double rotations to lift an accessed node. So
we still need another function (splay) to do a single rotation, if
needed, to complete the splay operation.