假设ocaml:
中有以下代码# let func a b = b a;;
val func : 'a -> ('a -> 'b) -> 'b = <fun>
函数类型是有意义的,因为我们可以看到,在rhs中,b
是一个以a
为参数的函数,因此b
的类型为('a ->'b)
,因此这也意味着结果的类型为'b
,而a的类型为'a
。所以我们得到val func : 'a -> ('a -> 'b) -> 'b = <fun>
。
然而,我没有得到的是
# let func a b c = a b c;;
val func : ('a -> 'b -> 'c) -> 'a -> 'b -> 'c = <fun>
根据第一个问题的逻辑,在rhs中可以清楚地看到,a
是一个接受b
和c
的函数,b
也是一个接受c
的函数。所以很明显,a
的类型是('a->'b->'c)
,b
的类型是('a->'b)
,c
的类型只是'a
。所以我得到的函数类型是(type of a) -> (type of b) -> (type of c) -> result
,替换上面的逻辑,我得到('a -> 'b ->'c) -> ('a ->'b) -> 'a -> 'c
,但这显然不是func
的真正类型。有人能解释一下我的逻辑出了什么问题吗?
同样,如果我写let func a b c = a b c
没有任何糖,它会是let func = fun a -> fun b -> (fun c -> a b c)
吗?谢谢你
您在问题中说:" andb
也是一个接受c
的函数"
这就是你的推理出错的地方。这是不存在的约束。表面上看,b
应用于c
,其实不然,它只是a
的第二个参数,而c
是a
的第三个参数。
如果用括号显式地说明优先级,b
永远不会应用于c
,这可能会更清楚:
# let func a b c = (a b) c;;
val func : ('a -> 'b -> 'c) -> 'a -> 'b -> 'c = <fun>
如果你写了let func a b c = ignore (b c) ; a b c;;
,那么b
将是一个应用于c
的函数。在这种情况下,推理将适用,您将有:
# let func a b c = ignore (b c) ; a b c;;
val func : (('a -> 'b) -> 'a -> 'c) -> ('a -> 'b) -> 'a -> 'c = <fun>
你的第二个问题是:
同样,如果我写
let func a b c = a b c
不加糖,它会是let func = fun a -> fun b -> (fun c -> a b c)
吗
是的,前者只是后者的简洁符号。括号甚至是不必要的:
# let func = fun a -> fun b -> fun c -> a b c;;
val func : ('a -> 'b -> 'c) -> 'a -> 'b -> 'c = <fun>
你的"显然";实际上是错误的,至少在你考虑b
和c
的类型时是错误的。如果对类型变量进行稍微不同的重命名,可能会更清楚:
# let func a b c = a b c;;
val func : ('b -> 'c -> 'd) -> 'b -> 'c -> 'd = <fun>
,它是一样的,只是开始一个'b
类型变量的名称。现在可能更清楚一点:a
的类型是'b -> 'c -> 'd
,b
的类型是'b
,c
的类型是'c
。该函数接受三个参数,将后两个参数(b
和c
)传递给第一个参数(a
),并返回它所返回的值('d
类型的值)