我试图了解这段代码正在做什么:
let rec size x =
match x with
[] -> 0
| _::tail -> 1 + (size tail) ;;
我知道这个表达式计算列表的大小,但我不明白它在代码中的位置逐一减少了列表。例如,我认为它需要从[1; 2; 3]到[2; 3]到[3],但是在哪里或如何做到这一点?我不明白。
感谢。
答案 0 :(得分:10)
OCaml中的列表是使用空列表([]
)和cons(::
)构造函数递归构建的。所以[1; 2; 3]
是1::2::3::[]
的句法糖。
通过使用模式x
(_::tail
表示我们忽略列表的头部)并调用相同的函数{{1},在每个步骤中减少_
来计算大小。在size
上。当列表为空并且tail
的模式成功时,该函数最终终止。
以下是如何计算[]
的简短说明:
size [1; 2; 3]
作为旁注,您可以从图中看到,需要在堆栈中存储大量信息才能计算 size 1::2::3::[]
~> 1 + size 2::3::[] // match the case of _::tail
~> 1 + 1 + size 3::[] // match the case of _::tail
~> 1 + 1 + 1 + size [] // match the case of _::tail
~> 1 + 1 + 1 + 0 // match the case of []
~> 3
。这意味着如果输入列表很长,你的函数可能会导致堆栈溢出错误,但这是另一个故事。
答案 1 :(得分:4)
根据this article,实际上您正在讨论的确切示例:
正如我们所看到的,列表可以是空的(列表的格式为
[]
),或者由第一个元素(其头部)和子列表(其尾部)组成。该列表的格式为h::t
。
如果列表匹配空列表,或者使用模式匹配来提取头部(第一项)和尾部(所有其他项),则提供的语句简单地给出0,然后使用递归来获得尾部的长度。
因此,_::tail
缩小列表,1 + (size tail)
计算大小。当然,|
之前的位是递归的终止条件。
如果被视为:
,可能更容易理解(在我看来)let rec size x = match x with
[] -> 0
| _::tail -> 1 + (size tail)
;;
(这实际上非常类似于链接页面中使用的格式,我只是稍微改了一下以排列->
符号)。
答案 2 :(得分:4)
实际上,这段代码使用模式匹配的力量来计算列表的大小。
match
表示您将尝试使x
以下列模式之一进入。
第一个[]
表示您的列表为空,因此其大小为0.而第二个_::tail
表示您有一个元素(*),后跟列表的其余部分,所以基本上大小是1 + size(rest of the list)
(*)下划线表示您不关心此元素的值。
答案 3 :(得分:4)
只要您与列表匹配,就可以匹配head::tail
形式的模式,其中head
将获取第一个元素的值,tail
将获得余数。
第二,你在Ocaml中匹配的任何模式,如果你愿意,你可以用下划线替换一个变量来说“匹配这里的东西,但我不打算实际使用它,所以我不给它的名字是“。因此,在这个程序中,不是编写head::tail -> 1 + (size tail)
,而是编写_::tail -> 1 + (size tail)
,因为它们实际上并没有使用第一个元素,只是确保它存在。
答案 4 :(得分:1)
它使用模式匹配来提取列表的尾部(命名为tail
),然后使用尾部调用自身。也许缺少的部分是模式匹配。