首先,我通常以命令式语言编程,这使我很难解释某些事情。首先是没有args和返回类型的函数。示例是展平列表的函数:
# let rec flat = function
[] -> []
| h :: t -> h @ flat t;;
val flat : 'a list list -> 'a list = <fun>
OCaml解释器如何知道:
flat
只需要一个参数,即“列表列表”。[] -> []
行进行检查?答案 0 :(得分:1)
let rec flat = function
[] -> []
| h :: t -> h @ flat t;;
您使用了function
个关键字。 function
是match ... with
的快捷方式。所以你写的函数就像
let rec flat l =
match l with
[] -> []
| h :: t -> h @ flat t
这就是为什么ocaml知道你的函数有一个参数
您的函数是递归的。 [] -> []
是基本情况,也是函数停止的地方。是的,口译员用[] -> []
检查它。
此外,函数必须至少具有unit parameter which is ()
或普通参数。如果一个函数没有任何东西,它就不是一个函数,而是一个具有固定值的变量。
我们举个例子:
let f1 = Random.int 10;
f1没有任何参数,即使没有()
(这里()
就像Java中没有任何参数的方法)。然后f1是由Random
生成的常数值。无论你什么时候打电话,f1都会被修复。
let f2 () = Random.int 10;
f2是一个功能。每次拨打f2()
时,Random
内部都会生成随机并返回。
答案 1 :(得分:1)
let rec flat = function
[] -> []
| h :: t -> h @ flat t;;
让我们一步一步完成这一步。正如您所料,function
关键字提供了一个功能。基本语法是function | pat1 -> branch1 | pat2 -> branch2
,你得到的是一个参数的函数,它试图依次匹配每个模式的参数,并且匹配结果的第一个模式是相应的分支。
这就是我们如何知道flat
是一个函数。此外,我们可以看到它的一个参数与[]
匹配,这是一个列表。所以flat
必须是一个列表的函数。我们看到如果输入为[]
,则输出为[]
,因此它是一个获取列表并返回列表的函数。
现在让我们看看第二种模式。 h :: t
是一个匹配列表的模式,并创建两个新的变量绑定:h
是列表的第一个元素,t
是所有其余元素。特别是,h
具有输入列表的元素所具有的任何类型。
如果您看一下如果此模式匹配成功,h @ flat t
会发生什么,我们会看到应用于@
和h
的列表并置运算符flat t
。这意味着h
必须是列表,并且必须与flat t
具有相同类型的列表。因此输入列表的元素是列表,函数的输出也是如此。
这会为您提供flat : 'a list list -> 'a list
。
要直接回答您的问题,flat
只需要一个参数,因为它是使用function
关键字定义的,而分支的返回值是值而不是函数(如果function
分支也是函数,这意味着flat
可能有两个或多个参数)。它是一个列表,因为模式匹配是针对列表构造函数的,它是一个列表列表,因为h
是列表的一个元素,并与@
运算符一起使用,这需要它的参数是列表,所以列表的元素是列表。
返回类型必须是列表实际上有三个原因:
[]
。@
的结果,@
返回列表flat t
以递归方式调用,然后作为@
的参数给出。由于它是@
的参数,因此它必须是一个列表,因此flat
必须返回一个列表。第三个bulet点特别有趣,因为它告诉你,不仅仅是你如何创建决定其类型的值,还有你如何使用它们。