let rec (l:int list) f int list =
match l with
| [] -> []
| hd::tl -> 2+tl
我想知道hd
是第一个元素,然后tl
是第二个元素,因为当我这样做时,我不断收到错误,如果tl
不是第二个元素我会访问第二个元素,对hd::tl
的深入解释将非常感谢,谢谢
答案 0 :(得分:5)
否tl
不是第二个元素,它是列表的其余部分,它的类型为'a list
。这里hd
和tl
只是您选择绑定到列表的第一个元素以及列表的其余部分的变量名称(即,包含除第一个元素之外的所有元素的列表) )。您可以选择其他名称,例如fst::rest
。在这种情况下,获得第二个元素就像fst::snd::rest
(或x::y::rest
一样简单 - 再次名称无关紧要。)
您尝试使用的是模式匹配。它是某些语言的一个特性,它提供了一种轻松解构复合数据结构的机制。我们的想法是,如果您以与构建数据结构相同的方式解构数据结构,例如,
let xs = [1;2;3;4]
这是解构
let [x1;x2;x3;x4] = xs
事实上,[x;y;...;z]
是更基本语法x :: y:: ... :: z :: []
的语法糖,因此构建[1;2;3;4]
列表的另一种方法是使用以下构造:1::2::3::4::[]
。这同样适用于相反的方向,例如,
let x1::x2::x3::x4::[] = xs
现在我们已准备好进行下一步,如果右侧的结构与左侧的结构不匹配,例如,
let [x;y;z] = [1;2]
或
let x::y::z::[] = 1::2::[]
在这种情况下,匹配将失败。在我们的运行时案例中。为了防止这种情况,并允许程序员处理其数据结构的所有可能配置,OCaml提供了match
构造,您可以在其中指定值结构的多个变体,并选择匹配的第一个,例如,
let orcish_length xs = match xs with
| [] -> 0
| x :: [] -> 1
| x :: y :: [] -> 2
| x :: y :: z :: [] -> 3
上述功能仅预测最多包含三个元素的列表(因为Orcs不能超过三个)。但我们可以。为此,我们将使用以下功能 - 如果列表模式的最后一个元素不是[]
(仅匹配且仅与空列表匹配,并指定列表末尾),但其他任何内容(即变量),然后该变量将绑定到所有元素,例如
let rec elvish_length xs = match xs with
| [] -> 0
| x :: [] -> 1
| x :: y :: [] -> 2
| x :: y :: z :: [] -> 3
| x :: y :: z :: leftovers -> 3 + elvish_length leftovers
现在,我们预计所有可能的列表模式。但是,该功能现在过于复杂(因为精灵很复杂)。现在,让我们最终得出一个普通的,人类可读的长度函数,
let rec length xs = match xs with
| [] -> 0
| x :: xs -> 1 + length xs
作为练习,尝试向自己证明此功能可以预测所有可能的列表。
答案 1 :(得分:3)
::
已读取cons
,并且是List.cons
的中缀版本。在像Ocaml这样的函数式语言中,list是一个链表,即{。{}}可以简化为:{/ p>
[e1; e2; e3; e4]
基本上,任何列表都可以简化为递归 cons(::)
/ \
e1 cons(::)
/ \
e2 cons(::)
/ \
e3 cons(::)
/ \
e4 [ ]
表达式树,这使得递归在Ocaml或类似的函数语言中非常有用。在每个级别,您可以将列表缩减为cons
及其head
,其中tail是列表减去其头部,并且可以进一步缩短到tail
。因此,通过上面的示例,您可以递归地缩小列表,直到通过模式匹配找到最后一个元素:
last :: []
请注意,let find_last li =
match li with
| [] -> None (* no element *)
| [last] -> Some last (* found last *)
| head :: tail -> find_last tail (* keep finding *)
;;
可以替换为[last]
,last::[]
替换为head::tail
。 重要的是,在任何时候,列表总是可以减少到List.cons head tail
,其中head :: tail
是第一个元素而head
是没有tail
的列表强>
模式匹配在匹配缩小列表的“形状”或状态时很有用。