OCaml中高阶函数和标记参数的行为解释

OCaml中高阶函数和标记参数的行为解释,ocaml,higher-order-functions,named,Ocaml,Higher Order Functions,Named,以从RWOCaml派生的示例为例: utop # let divide ~first ~second = first / second;; val divide : first:int -> second:int -> int = <fun> utop # let apply_to_tuple_3 f (first,second) = f second first;; val apply_to_tuple_3 : ('a -> 'b -> 'c) ->

以从RWOCaml派生的示例为例:

utop # let divide ~first ~second = first / second;;
val divide : first:int -> second:int -> int = <fun>

utop # let apply_to_tuple_3 f (first,second) = f second first;;
val apply_to_tuple_3 : ('a -> 'b -> 'c) -> 'b * 'a -> 'c = <fun>

utop # apply_to_tuple_3 divide;;
Error: This expression has type first:int -> second:int -> int
       but an expression was expected of type 'a -> 'b -> 'c

是否有任何理由拒绝第一次调用?

带有标记参数的函数的类型取决于标签及其出现的顺序。调用此类函数时,提供的参数顺序具有灵活性。事实上,如果你提供了所有的参数,你可以省略标签

但是,当将这些函数本身作为值传递时,没有这种灵活性。您只有一个标记为“类型”的对象可以使用

真实世界OCaml的第42页介绍了这一点:高阶函数和标签


(如果您要问为什么会出现这种情况,我只能假设如果您允许这种灵活性,类型检查将变得困难或不可能。)

我要问的是,在这种特定情况下,如果客户端不要求显示名称,则类型不兼容。带有标签的类型与没有标签的类型不兼容。当您使用带标签的参数调用函数时,编译器会很灵活,但在其他情况下不会。您有其他案例之一。类型检查器认为它们不兼容。原因是它们是兼容的,除非我遗漏了什么。除了类型检查器在这种情况下非常粗糙,这意味着我们需要进行一些手动包装之外,可能没有其他原因造成这种不同。那很好。我只是想知道是否有什么真正的原因我可能错过了。没有原因。只是类型检查器和语言实现的一个限制。这两种类型显然是不等价的。也就是说,它们中的一个比另一个更具体(并且不是以参数多态的方式)。我认为,你想要的是一种亚类型。OCaml不推断子类型,因此您必须手动注释子类型。我怀疑如果有人想在类型系统上投入工作,这可能会起作用。同时,您可以编写一个类似于此注释的函数:
let annotate f first second=f~ first~ second
utop # let divide_an x y = divide x y;;
val divide_an : int -> int -> int = <fun>
utop # apply_to_tuple_3 divide_an;;
- : int * int -> int = <fun>