函数式语言类型推断混乱



假设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是一个接受bc的函数,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的第二个参数,而ca的第三个参数。

如果用括号显式地说明优先级,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>

你的"显然";实际上是错误的,至少在你考虑bc的类型时是错误的。如果对类型变量进行稍微不同的重命名,可能会更清楚:

# 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。该函数接受三个参数,将后两个参数(bc)传递给第一个参数(a),并返回它所返回的值('d类型的值)

相关内容

  • 没有找到相关文章