Revisiting the post on Braun Trees I noticed that, while pedagogical, the implementation of the root replacement operation
rep can be streamlined a bit. By inlining the mutually recursive
siftdown, specializing on the matches and adding guards, the result is as follows:
let rec rep compare e = function | N (_, (N (el, _, _) as l), E) when compare el e < 0 -> N (el, rep compare e l, E) | N (_, (N (el, _, _) as l), (N (er, _, _) as r)) when compare el e < 0 || compare er e < 0 -> if compare el er < 0 then N (el, rep compare e l, r) else N (er, l, rep compare e r) | N (_, l, r) -> N (e, l, r) | E -> failwith "empty heap"
The guards are the strongest possible in order to minimize the needs to descend to the children. The conditional under the second case could be in turn lifted to a guard, since (el < e ∨ er < e) ∧ el < er ⇒ el < e ∧ el < er, and similarly for the
else case, but the loss of simplicity is quite substantial in my opinion.