【问题标题】:The right way to use a data structure in OCaml在 OCaml 中使用数据结构的正确方法
【发布时间】:2013-01-04 15:07:55
【问题描述】:

好的,我在 OCaml 中写了一个binary search tree

type 'a bstree = 
    |Node of 'a * 'a bstree * 'a bstree
    |Leaf


let rec insert x = function
    |Leaf -> Node (x, Leaf, Leaf)
    |Node (y, left, right) as node -> 
        if x < y then
            Node (y, insert x left, right)
        else if x > y then
            Node (y, left, insert x right)
        else
            node

我猜上面的代码没有问题。

用的时候我写

let root = insert 4 Leaf

let root = insert 5 root

...

这是use/insert 到树的正确方法吗?

我的意思是,我想我不应该声明根并且每次我再次更改变量根的值,对吧?

如果是这样,我怎样才能始终保持根并可以随时向树中插入值?

【问题讨论】:

    标签: data-structures functional-programming ocaml


    【解决方案1】:

    这看起来像是插入树的好功能代码。它不会在插入过程中改变树,而是创建一个包含该值的新树。不可变数据的基本思想是你不“保留”东西。您计算值并将它们传递给新函数。例如,这是一个从列表创建树的函数:

    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)
    

    (希望我没有破坏你的作业!)

    【讨论】:

    • 感谢您的回复。因此,我知道将列表转换为 bst 是一个过程,最终值是树并绑定到 tree_of_list。但是,如果列表稍后再获得一个值怎么办?我应该再次运行转换吗?基本上我想问的是我应该更改变量的值(代码中的tree_of_list)吗?
    • FP 的本质是你不改变值。这就是你需要环绕你的头!列表以后无法获得新值——它是不可变的。要进一步处理树,您可以将其传递给新函数。
    • 好的,所以它与改变变量的值无关?简单地说,如果我有let x = 1;;,那么我有let x = 2;;,没关系,对吧?
    • 这是两个不同的xs,而不是同一个x。顶层这样有点误导。
    • remove x tree 将返回一个没有x 的新树。如果您想回收该元素使用的空间,则必须让旧树超出范围,以便垃圾收集器将其清除。
    猜你喜欢
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-06
    • 2017-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多