以下代码段来自官方OCaml website:
# 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具有功能性,因此我倾向于认为列表不是可变的-正确吗?如果要更改列表,则基本上需要使用要添加的元素(或要缺失的元素)生成一个新列表。这是正确的理解吗?
答案 0 :(得分:2)
是的,基本情况是这样:
| smaller -> smaller
match
表达式的第一个模式与长度2或更大的任何列表匹配。 (最好确保您知道为什么会这样。)
由于OCaml按顺序匹配模式,因此基本情况匹配长度为0和1的列表。这就是程序员选择名称smaller
的原因。他们在想“这是一个较小的列表”。
match语句的各部分大致如下:
| pattern -> result
模式中的任何名称都绑定到与模式匹配的部分值(如您所说)。因此smaller
被绑定到整个列表。因此,总而言之,match
的第二部分说,如果列表的长度为0或1,则结果应该只是列表本身。
OCaml中的列表是不可变的,因此该函数的结果不可能是列表的修改版本。结果是一个新列表,除非该列表已经是一个简短列表(长度为0或1)。
所以,您所说的OCaml列表的不变性是完全正确的。