代码之家  ›  专栏  ›  技术社区  ›  REALFREE

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

  •  2
  • REALFREE  · 技术社区  · 15 年前

    比如说

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

    我想访问标记值并修改它。

    我能想到的是

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

    我知道这不是递归语法,但我至少想知道如何处理这个问题

    3 回复  |  直到 15 年前
        1
  •  4
  •   0xFF    15 年前

    如果我理解你的问题,你可以用两种不同的方法来实现你想要的。

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

    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;;
    

    let rec get_modified_xml xml =
        match xml with
            Element (tag, xlist) -> if (!tag = "phoneNumber") then
                                        Element(ref "phone", List.map (fun element -> get_modified_xml element) xlist)
                                    else
                                        Element (tag, List.map (fun element -> get_modified_xml element) xlist)
            | _ -> xml;;
    
    
    get_modified_xml xml_test;;
    

    输出:

    - : xml =
    Element ({contents = "person"},
     [CharData "text0"; Element ({contents = "phone"}, [CharData "text2"]);
      CharData "text1"; Element ({contents = "phone"}, [CharData "text3"])])
    
        2
  •  2
  •   newacct    15 年前

    首先,你说的“修改”是什么意思?只返回一个新的更改的值是可以的,还是必须改变原始结构?因为在OCaml中,唯一可变的是数组元素、字符串元素、显式标记为可变的记录中的字段(包括 ref

        3
  •  1
  •   nlucaroni    15 年前

    这是有区别的,因为在函数式语言中,我们通常处理不变的数据结构。我想你想问的是,如何返回一个新的结构,用一个指定的标记替换另一个。撇开迂腐不谈,在函数式语言中这是一件很自然的事情,你很少会考虑到这一点。

    让我们完全定义您正在使用的结构。我另外定义了tag——我假设它是一个字符串。

    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)
    

    这是一个体面的,简单的解决办法,我认为你的问题。不过,这方面有很多问题;如果值不存在,它不会进行错误检查,并且每次都会复制整个数据结构——这是由于 List.map

    推荐文章