ocaml 中的递归函数和模式匹配



以下代码片段来自OCaml官方网站:

# let rec compress = function
| a :: (b :: _ as t) -> if a = b then compress t else a :: compress t
| smaller -> smaller;;
val compress : 'a list -> 'a list = <fun>

上面的函数"压缩"了一个包含连续重复元素的列表,例如:

# compress ["a";"a";"a";"a";"b";"c";"c";"a";"a";"d";"e";"e";"e";"e"];;
- : string list = ["a"; "b"; "c"; "a"; "d"; "e"]

我正在理解上述代码的逻辑。我习惯于命令式编码,所以这种递归的函数式方法,加上OCamls简洁但晦涩难懂的语法,让我很挣扎。

例如,基本情况在哪里?是smaller -> smaller吗?我知道smaller是一个变量或标识符,但它返回的是什么(对于这里发生的事情,返回甚至是 OCaml 中的正确术语(?

我知道 OCaml 中的列表是单链接的,所以我也想知道是否正在生成一个新列表,或者是否正在剪切现有列表的元素?由于 OCaml 是功能性的,我倾向于认为列表是不可变的 - 这是正确的吗?如果要更改列表,则基本上需要生成一个新列表,其中包含要添加的元素(或要删除的元素(。这是正确的理解吗?

是的,基本情况是这样的:

| smaller -> smaller

match表达式的第一个模式匹配长度为 2 或更大的任何列表。(最好确保您了解为什么会这样。

由于 OCaml 按顺序匹配模式,因此基本情况匹配长度为 0 和 1 的列表。这就是程序员选择smaller这个名字的原因。他们在想"这是一个较小的清单"。

匹配语句的各个部分通常如下所示:

| pattern -> result

模式中的任何名称都绑定到与模式匹配的值部分(如您所说(。因此,smaller绑定到整个列表。总而言之,match的第二部分说,如果列表的长度为 0 或 1,则结果应该只是列表本身。

OCaml 中的列表是不可变的,因此函数的结果不可能是列表的修改版本。结果是一个新列表,除非该列表已经是一个短列表(长度为 0 或 1(。

所以,你所说的OCaml列表的不变性是完全正确的。

最新更新