如何访问ocaml数据类型并递归地修改值?
我正在学习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 *) 我知道这不是递归语法,但我至少想知道如何
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)