我正在学习Ocaml并且完全失去了解决这个问题的方法。
这是一个例子。
让我们说
type xml = Element of tag * xml list | CharData of string;;
我希望访问标记值并对其进行修改。
我能想到的是
match xml with
Element (tag, xlist) -> (* do something *)
| CharData str -> (* do something *)
我知道这不是递归语法,但我想知道至少如何处理这个
答案 0 :(得分:4)
如果我理解你的问题,你可以通过两种不同的方式实现你想要的目标。
您在标记类型上使用可变数据结构,如下例所示:
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”:
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"])])
答案 1 :(得分:2)
首先,“修改”是什么意思?是否可以只返回一个新的更改值,或者您是否真的必须改变原始结构?因为在OCaml中,唯一可变的东西是数组元素,字符串元素,显式标记为可变的记录中的字段(包括ref
数据结构),以及明确标记为可变的对象中的字段。
答案 2 :(得分:1)
我认为你在这里松散地使用修改这个词 - 这对你没有任何过错。我怀疑那里有正确的人会在他们的递归数据结构中使用引用;并且是新的,我很难证明你的意思是字面意义。
存在差异,因为在函数式语言中,我们通常处理不可变数据结构。我认为你要问的是,如何返回一个新结构,其中指定的标签被另一个替换。除了Pedantry之外,在函数式语言中这是很自然的事情,它将是你很少考虑的事情。
让我们完全定义您正在使用的结构。我另外定义了标签 - 我假设它是一个字符串。
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
调用开始。有了更多细节,我想我们可以为您提供更好的解决方案。