Taking Étienne Millon's answer a bit further, we can use _ when binding parts of patterns we don't care about.
let rec deleteNode tree value =
match tree with
| Empty -> Empty
| Node (left, nodeValue, right) when value < nodeValue ->
Node (deleteNode left value, nodeValue, right)
| Node (left, nodeValue, right) when value > nodeValue ->
Node (left, nodeValue, deleteNode right value)
| Node (Empty, _, Empty) ->
Empty
| Node (Empty, _, right) ->
right
| Node (left, _, Empty) ->
left
| Node (left, nodeValue, right) ->
let newValue = minValue right in
Node (left, newValue, deleteNode right newValue)
And then let's reorder the patterns a bit. The basic logic is unaffected. We can also eliminate the redundant cases involving returning the right branch.
let rec deleteNode tree value =
match tree with
| Node (left, nodeValue, right) when value < nodeValue ->
Node (deleteNode left value, nodeValue, right)
| Node (left, nodeValue, right) when value > nodeValue ->
Node (left, nodeValue, deleteNode right value)
| Empty -> Empty
| Node (Empty, _, right) ->
right
| Node (left, _, Empty) ->
left
| Node (left, nodeValue, right) ->
let newValue = minValue right in
Node (left, newValue, deleteNode right newValue)
OCaml allows us to "or" patterns together when the same names are bound in all of the patterns. That is not the case for Empty, Node (Empty, _, right), and Node (left, _, Empty) but it can be.
let rec deleteNode tree value =
match tree with
| Node (left, nodeValue, right) when value < nodeValue ->
Node (deleteNode left value, nodeValue, right)
| Node (left, nodeValue, right) when value > nodeValue ->
Node (left, nodeValue, deleteNode right value)
| Empty as t
| Node (Empty, _, t)
| Node (t, _, Empty) ->
t
| Node (left, nodeValue, right) ->
let newValue = minValue right in
Node (left, newValue, deleteNode right newValue)
A final thought is that it's fairly idiomatic if one looks at the standard library as a guide for the deleteNode function to take the value to delete as its first argument.
let rec deleteNode value = function
| Node (left, nodeValue, right) when value < nodeValue ->
Node (deleteNode value lef, nodeValue, right)
| Node (left, nodeValue, right) when value > nodeValue ->
Node (left, nodeValue, deleteNode value right)
| Empty as t
| Node (Empty, _, t)
| Node (t, _, Empty) ->
t
| Node (left, nodeValue, right) ->
let newValue = minValue right in
Node (left, newValue, deleteNode newValue right)
This facilitates using the |> and @@ operators to clean up code and make it easier to understand.
E.g.
my_tree |> deleteNode 4 |> deleteNode 3 |> deleteNode 5
Vs.
deleteNode (deleteNode (deleteNode my_tree 4) 3) 5