这看起来像是插入树的良好功能代码。它不会在插入过程中改变树,而是创建一个包含该值的新树。不可变数据的基本思想是你不“保留”东西。您计算值并将它们传递给新函数。例如,这是一个从列表创建树的函数:
let tree_of_list l = List.fold_right insert l Leaf
它通过将当前树传递给对insert
.
以这种方式思考是值得学习的,因为 FP 的许多好处都来自于不可变数据的使用。然而,OCaml 是一种混合范式语言。如果您愿意,您可以使用引用(或可变记录字段)在更改值时“保留”一棵树,就像在普通命令式编程中一样。
编辑:
您可能会认为以下会话显示了对变量 x 的修改:
# let x = 2;;
val x : int = 2
# let x = 3;;
val x : int = 3
#
然而,看待这一点的方式是,这是两个不同的值,碰巧都被命名为 x。因为名称相同,所以 x 的旧值被隐藏。但是,如果您有另一种访问旧值的方法,它仍然会存在。也许以下将显示事情是如何工作的:
# let x = 2;;
val x : int = 2
# let f () = x + 5;;
val f : unit -> int = <fun>
# f ();;
- : int = 7
# let x = 8;;
val x : int = 8
# f ();;
- : int = 7
#
创建一个名为x
8 的新事物不会影响f
它的作用。它仍然使用x
定义时存在的旧版本。
编辑2:
从树中删除一个不可变的值类似于添加一个值。即,您实际上并没有修改现有的树。您创建了一个没有您不想要的值的新树。正如插入不会复制整个树(它会重复使用前一棵树的大部分),所以删除也不会复制整个树。树中未更改的任何部分都可以在新树中重新使用。
编辑 3
这是一些从树中删除值的代码。它使用一个辅助函数来连接两棵已知不相交的树(此外,a 中的所有值都小于 b 中的所有值):
let rec adjoin a b =
match a, b with
| Leaf, _ -> b
| _, Leaf -> a
| Node (v, al, ar), _ -> Node (v, al, adjoin ar b)
let rec delete x = function
| Leaf -> Leaf
| Node (v, l, r) ->
if x = v then adjoin l r
else if x < v then Node (v, delete x l, r)
else Node (v, l, delete x r)
(希望我没有破坏你的作业!)