OCaml函数帮助解析列表列表

时间:2011-11-11 01:01:34

标签: list ocaml

我正在尝试创建一个OCaml函数rv,它将遍历列表列表并将元素重新组织到另一个列表列表中,这样第一个列表就包含每个原始列表的第一个元素,第二个列表由每个列表的第二个元素组成。

一个例子:
[["a"; "b"; "c"]; ["d"; "e"; "f"]]变成了 [["a"; "d"]; ["b"; "e"]; ["c"; "f"]]

我已经有了一个函数集合,它将获取列表列表并从每个列表中提取某个索引的元素。所以基本上使用前面的例子,我可以说gather(list, 1)并获得["b"; "e"]。我需要一种方法来完成List.length次,并为每个元素索引使用聚集。

这导致我如此麻烦的原因是因为适用的限制(是的,这是针对学校的)。我不允许使用循环或局部/全局变量。我也不允许在函数体内使用'let'。是否有另一种方法可以递归地为每个元素索引使用gather?是否还有其他函数我将以递归方式使用gather,然后在rv中重用该函数?如果是这样,你会怎么做?

1 个答案:

答案 0 :(得分:7)

要克服对循环的限制,请使用递归函数。

使用let的限制有点愚蠢。您可以通过将参数传递给函数来解决它,在某种程度上,编写(function x -> e) v而不是let x = v in e。但请将其视为暗示您应该利用List.mapList.fold_left等功能。

一般来说,列表不是数组;它们并不意味着使用元素的索引进行访问。当然,你可以做到,但它既麻烦又低效。访问列表的自然方式是使用模式匹配或List.hdList.tl函数来拆分第一个元素和列表的其余部分,或者使用List.map等函数遍历整个清单。

例如,如果您需要的只是每个列表的第一个元素,那么您可以使用

List.map List.hd lists

List.map List.tl lists给出了每个列表的其余部分。这表明了一种递归方法:结果的头部是List.map List.hd lists,结果的尾部是List.map List.tl lists的转置。

let rec transpose lists =
  List.map List.hd lists :: transpose (List.map List.tl lists)

现在,显然,我们需要在某个时候终止。假设所有列表都具有相同的长度,我们需要在列表为空时停止,我们可以通过查看第一个列表来测试。我将把它留作练习。

为了理解这段代码的作用,我建议使用#trace指令在Ocaml toplevel中键入它,并在几个示例中观察操作。为此,如果您使transpose函数单态化,将会有所帮助。

# let rec tranpose (lists : string list list) = …;;
val transpose : string list list -> string list list = <fun>
# #trace transpose;;
transpose is now traced.
# transpose [["a"; "b"; "c"]; ["d"; "e"; "f"]];;
transpose <-- [["a"; "b"; "c"]; ["d"; "e"; "f"]]
transpose <-- [["b"; "c"]; ["e"; "f"]]
transpose <-- [["c"]; ["f"]]
transpose <-- [[]; []]
transpose --> []
transpose --> [["c"; "f"]]
transpose --> [["b"; "e"]; ["c"; "f"]]
transpose --> [["a"; "d"]; ["b"; "e"]; ["c"; "f"]]
- : string list list = [["a"; "d"]; ["b"; "e"]; ["c"; "f"]]