似乎在某些情况下,如果函数的顺序是正确的,就可以使用带标签的参数调用函数。
let f ~x ~y = Format.sprintf "%d %s" x y;;
f 3 "test";;成功地运行,但是
f "test" 3;;错误消息失败。
Line 1, characters 2-8:
Error: This expression has type string but an expression was expected of type
int对于带有可选参数的函数,如果不传递可选参数,它似乎可以工作:
let f ?(x = 1) ~y () = Format.sprintf "%d %s" x y;;
f "help" ();;成功了,但是
f 2 "help" ();;错误消息失败。
Line 1, characters 4-10:
Error: The function applied to this argument has type
?x:int -> y:string -> string
This argument cannot be applied without label在可能的情况下,是否有一条一般规则?
发布于 2019-10-10 13:07:00
如果应用程序是总计(即提供了所有必需的参数),如果函数的返回类型不是类型变量,则可以省略标签。可选参数的参数必须始终由标签传递。
我们来举几个例子,
let example1 ?(opt=0) ~a ~b ~c unlabeled =
opt + a + b + c + unlabeled;;
example1 1 2 3 4;;
- : int = 10在这里,我们能够在没有标签的情况下应用所有参数,因为我们提供了所有必需的参数(不需要可选参数,因此不需要名称),并且结果类型不是多态的。但是,如果我们将List.fold函数从Core或ListLabels中取出来,那么它的类型是
'a list -> init:'accum -> f:('accum -> 'a -> 'accum) -> 'accum然后我们会得到,
List.fold [1;2;3;4] 0 (+);;
- : init:(int -> (int -> int -> int) -> '_weak1) ->
f:((int -> (int -> int -> int) -> '_weak1) ->
int -> int -> (int -> int -> int) -> '_weak1) ->
'_weak1而不是10,这是人们所期望的。原因是因为生成的类型'accum是一个类型变量,所以它也可以是一个函数,例如,int -> int或string -> int -> unit等等--所有这些类型都与'accum类型匹配。这基本上意味着这个函数接受可能无限数量的位置参数。因此,我们提供的所有参数都被解释为位置,因此,我们永远无法填写标记的参数,因此,我们的应用程序没有被总计。这实际上使我们在投递开始时对规则的原始定义变得多余--因为一个应用程序(它的类型由类型变量表示)永远不可能是总计的。
请注意,只有当返回类型是类型变量时才会出现此问题,而不只是包含一些类型变量,例如,我们可以很容易地省略带有List.map函数的标签,例如,给定具有类型的List.map
'a list -> f:('a -> 'b) -> 'b list我们可以很容易地应用它。
# List.map [1;2;3] ident;;
- : int Core_kernel.List.t = [1; 2; 3]尽管如此,人们通常认为省略标签是一种错误的做法。主要是因为多态返回类型的警告,并因为它使得标记参数的顺序很重要,这有点违背直觉。
发布于 2019-10-10 08:23:56
是的,这是有一般规则的。来自手册
形式参数和参数根据各自的标签进行匹配,没有标签被解释为空标签。这允许在应用程序中交换参数。还可以对任何参数部分应用一个函数,为其余参数创建一个新函数。 如果一个函数的几个参数都带有相同的标签(或没有标签),它们之间就不会通勤,而顺序就会起作用。但他们仍然可以与其他论点通勤。 作为上述参数匹配规则的一个例外,如果应用程序为(省略所有可选参数),则可以省略标签。在实践中,许多应用程序都是总计的,因此通常可以省略标签。
https://stackoverflow.com/questions/58315641
复制相似问题