函数类型 ('a -> 'a) -> int -> 'a -> 'a 和 ('a -> 'a) -> int -> ('a -> 'a) 之间有什么区别?

What is the difference between function type ('a -> 'a) -> int -> 'a -> 'a and ('a -> 'a) -> int -> ('a -> 'a)?

当我写一个 Ocaml 函数来递归地组合同一个函数 n 次时,我是这样做的:

let rec compose f n = 
  (fun x -> if n = 1 then f x else ((compose f (n-1))) (f x));; 

它给出了类型

val compose : ('a -> 'a) -> int -> 'a -> 'a = <fun>

类型有什么区别

('a -> 'a) -> int -> 'a -> 'a

并输入

('a -> 'a) -> int -> ('a -> 'a)

?

对于后一种类型,类似的 compose 函数看起来如何?

它们之间没有区别。但有时库的作者使用括号来表示,计算实际上是分阶段的,因此最好部分地应用它,这样你可以获得更有效的功能,而不是每次都应用它。但是从类型系统的角度来看,这些功能是完全相同的,因为 -> 类型运算符关联到右边。

作为对@ivg 回答的补充,这是我犯的一个错误。考虑这两个具有相同类型 int -> int -> int 的函数。 (;; 添加到顶层粘贴)

let f a b = 
  let ai = 
    Printf.printf "incrementing %d to %d\n" a (a + 1);
    a + 1 in
  b + ai;;

let f' a = 
  let ai = 
    Printf.printf "incrementing %d to %d\n" a (a + 1);
    a + 1 in
  function b -> b + ai;;

如果您部分申请

let f_1 = f 1;;
let f'_1 = f' 1;;

您会看到不同之处。我的想法是 ff' 做的事。实际上,Ocaml 很急切,但 没有 急切地开始在偏函数应用程序中求值,直到用完所有参数。为了指出区别,将 f' 的类型写成 int -> (int -> int) 是有意义的。