如何访问ocaml数据类型并递归地修改值?

如何访问ocaml数据类型并递归地修改值?,ocaml,types,Ocaml,Types,我正在学习Ocaml,但对如何处理这一问题感到非常困惑 下面是一个例子 比方说 type xml = Element of tag * xml list | CharData of string;; 我想访问标记值并修改它 我能想到的是 match xml with Element (tag, xlist) -> (* do something *) | CharData str -> (* do something *) 我知道这不是递归语法,但我至少想知道如何

我正在学习Ocaml,但对如何处理这一问题感到非常困惑

下面是一个例子

比方说

type xml = Element of tag * xml list | CharData of string;;
我想访问标记值并修改它

我能想到的是

match xml with 
    Element (tag, xlist) -> (* do something *) 
|   CharData str -> (* do something *)

我知道这不是递归语法,但我至少想知道如何处理这个问题。首先,你说的“修改”是什么意思?只返回一个新的已更改的值可以吗,或者您实际上必须修改原始结构吗?因为在OCaml中,唯一可变的是数组元素、字符串元素、显式标记为可变的记录中的字段(包括
ref
数据结构)和显式标记为可变的对象中的字段。

如果我理解你的问题,你可以通过两种不同的方式实现你想要的

在标记类型上使用可变数据结构,如以下示例所示:

type tag = string ref;;
type xml = Element of tag * xml list | CharData of string;;

let xml_test = Element (ref "person",
   [CharData "text0";
    Element (ref "phoneNumber", [CharData "text2"]);
    CharData "text1";
    Element (ref "phoneNumber", [CharData "text3"])]);;

let modify_tag tag new_value=
    tag := new_value;;

let rec modify_and_print_xml xml =
    match xml with 
        Element (tag, xlist) -> modify_tag tag (!tag^"_modified");
                                print_string (!tag); print_newline ();

                                (*here you do the recursive call*)
                                List.iter (fun element -> modify_and_print_xml element) xlist

        |CharData str -> print_string str; print_newline ();;

modify_and_print_xml xml_test;;
否则,而且由于您是函数式编程的新手,考虑它的最佳方式不是就地修改标记值,而是构造一个具有修改标记的新xml值(这是编写纯函数式代码并消除副作用所应该做的)

下面是一个示例,假设您希望将每个名为“phoneNumber”的标记修改为“phone”:

输出:

- : xml =
Element ({contents = "person"},
 [CharData "text0"; Element ({contents = "phone"}, [CharData "text2"]);
  CharData "text1"; Element ({contents = "phone"}, [CharData "text3"])])

我认为你在这里使用的是“随意修改”这个词——这对你来说没有错。我怀疑任何头脑正常的人都不会在递归数据结构中使用引用;作为一个新手,我很难证明你是这么说的

这是有区别的,因为在函数式语言中,我们通常处理不可变的数据结构。我想你想问的是,如何返回一个新的结构,其中一个指定的标记被另一个替换。撇开迂腐,这是一个很自然的事情,在功能语言,它将是你将只考虑很少。 让我们完全定义您正在使用的结构。我另外定义了标记——我假设它是一个字符串

type tag = string
type xml = Element of tag * xml list | CharData of string;;
以及函数的签名(因此我们很清楚我们要实现什么)

对于我认为你的问题,这是一个体面、简单的解决方案。不过,这方面存在许多问题;如果该值不存在,它不会执行错误检查,并且每次都会复制整个数据结构——由于调用了
List.map
。有了更多的细节,我想我们可以为您提供更好的解决方案

type tag = string
type xml = Element of tag * xml list | CharData of string;;
val replace_tag : string -> string -> xml -> xml

let rec replace_tag from_tag to_tag = function
    (* nothing to do here... *)
    | (CharData _ ) as x -> x
    (* an element with the proper tag; call function on its contents *)
    | Element (tag, xmlist) when tag = tag_from ->
        let xmlist = List.map (fun t -> replace_tag from_tag to_tag t) xmlist in
        let ntag,ncontent = f tag xmlist in
        Element (tag_to,xmlist)
    (* look into each element of xml contents *)
    | Element (tag, xmlist) ->
        let xmlist = List.map (fun t -> replace_tag from_tag to_tag t) xmlist in
        Element(tag,xmlist)