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.