相互递归的类型推断

发布于 2024-09-27 01:59:19 字数 468 浏览 5 评论 0原文

我一直在思考类型推断如何在以下 OCaml 程序中工作:

let rec f x = (g x) + 5
and g x = f (x + 5);;

当然,该程序毫无用处(永远循环),但是类型呢? OCaml 说:

val f : int -> int = <fun>
val g : int -> int = <fun>

这正是我的直觉,但是类型推断算法如何知道这一点?

假设算法首先考虑“f”:它可以得到的唯一约束是“g”的返回类型必须是“int”,因此它自己的返回类型也是“int”。但它无法通过“f”的定义推断其参数的类型。

另一方面,如果它首先考虑“g”,它可以看到它自己的参数的类型必须是“int”。但如果之前没有考虑过“f”,它就无法知道“g”的返回类型也是“int”。

它背后有何魔力?

I've been thinking about how type inference works in the following OCaml program:

let rec f x = (g x) + 5
and g x = f (x + 5);;

Granted, the program is quite useless (looping forever), but what about the types?
OCaml says:

val f : int -> int = <fun>
val g : int -> int = <fun>

This would exactly be my intuition, but how does the type inference algorithm know this?

Say the algorithm considers "f" first: the only constraint it can get there is that the return type of "g" must be "int", and therefore its own return type is also "int". But it cannot infer the type of its argument by the definition of "f".

On the other hand, if it considers "g" first, it can see that the type of its own argument must be "int". But without having considered "f" before, it can't know that the return type of "g" is also "int".

What is the magic behind it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

影子是时光的心 2024-10-04 01:59:19

假设算法首先考虑“f”:它可以得到的唯一约束是“g”的返回类型必须是“int”,因此它自己的返回类型也是“int”。但它无法通过“f”的定义推断其参数的类型。

它无法将其推断为具体类型,但可以推断出某些内容。即:f 的参数类型必须与g 的参数类型相同。所以基本上在查看 f 后,ocaml 知道以下有关类型的信息:

for some (to be determined) 'a:
f: 'a -> int
g: 'a -> int

在查看 g 后,它知道 'a 必须是 int

要更深入地了解类型推断算法的工作原理,您可以阅读有关 Hindley-Milner 类型推断这篇博文,看起来比维基百科的文章友好得多。

Say the algorithm considers "f" first: the only constraint it can get there is that the return type of "g" must be "int", and therefore its own return type is also "int". But it cannot infer the type of its argument by the definition of "f".

It can't infer it to a concrete type, but it can infer something. Namely: the argument type of f must be the same as the argument type of g. So basically after looking at f, ocaml knows the following about the types:

for some (to be determined) 'a:
f: 'a -> int
g: 'a -> int

After looking at g it knows that 'a must be int.

For a more in-depth look on how the type inference algorithm works, you can read the Wikipedia article about Hindley-Milner type inference or this blog post, which seems to be much friendlier than the Wikipedia article.

謸气贵蔟 2024-10-04 01:59:19

这是我对所发生事情的心理模型,它可能与现实相符,也可能不相符。

let rec f x =

好的,此时我们知道 f 是一个接受参数 x 的函数。因此我们有:

f: 'a -> 'b
x: 'a

对于一些 'a'b。下一步:

(g x)

好的,现在我们知道 g 是一个可以应用于 x 的函数,因此我们将其添加

g: 'a -> 'c

到信息列表中。继续...

(g x) + 5 

啊哈,g的返回类型必须是int,所以现在我们已经解决了'c=int。此时我们有:

f: 'a -> 'b
x: 'a
g: 'a -> int

继续...

and g x =

好吧,这里有一个不同的 x,让我们假设原始代码有 y,以使事情更加明显。也就是说,让我们将代码重写为

and g y = f (y + 5);; 

“Ok”,现在

and g y = 

我们的信息是:

f: 'a -> 'b
x: 'a
g: 'a -> int
y: 'a

因为 yg 的参数...我们继续:

f (y + 5);; 

并且这从 y+5 告诉我们,y 的类型为 int,这解决了 'a=int 问题。由于这是 g 的返回值,我们已经知道它必须是 int,所以这就解决了 'b=int。一步完成了很多工作,如果代码是

and g y = 
    let t = y + 5 in
    let r = f t in
    f r;; 

,那么第一行将显示 y 是一个 int,从而解决 'a,然后下一行会说 r 的类型为 'b,最后一行是 g 的返回,这解决了 'b=int

Here is my mental model of what goes on, which may or may not match reality.

let rec f x =

Ok, at this point we know that f is a function that takes argument x. Thus we have:

f: 'a -> 'b
x: 'a

for some 'a and 'b. Next:

(g x)

Ok, now we know g is a function that can be applied to x, so we add

g: 'a -> 'c

to our list of information. Continuing...

(g x) + 5 

Aha, the return type of g must be int, so now we have solved 'c=int. At this point we have:

f: 'a -> 'b
x: 'a
g: 'a -> int

Moving on...

and g x =

Ok, there's a different x here, let's assume the original code had y instead, to keep things more obvious. That is, let's rewrite the code as

and g y = f (y + 5);; 

Ok, so we are at

and g y = 

so now our info is:

f: 'a -> 'b
x: 'a
g: 'a -> int
y: 'a

since y is an argument to g... and we keep going:

f (y + 5);; 

and this tells us from y+5 that y has type int, which solves 'a=int. And since this is the return value of g, which we already know must be int, this solves 'b=int. That was a lot in one step, if the code were

and g y = 
    let t = y + 5 in
    let r = f t in
    f r;; 

then the first line would show y is an int, thus solving for 'a, and then the next line would say that r has type 'b, and then the final line is the return of g, which solves 'b=int.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文