我正在尝试实现一种自定义语言,允许从最后一个语句推断出函数返回类型。但是,当发现直接或间接递归函数调用时,类型推断系统显然会失败。
func factorial(a:int) ->
if a == 0
1
else
a * factorial(a - 1)
例如,即使参数类型未指定,F#也会这样做:
let rec fact i =
if i = 0 then 1 else i * fact (i-1)
这个系统如何运作?
答案 0 :(得分:13)
F#类型检查器使用Damas-Hindley-Milner类型推断算法。阶乘的例子大致可以解释如下:
在fact
的声明中,我们的格式为tx -> ty
和tx = t(i)
,其中t(i)
是值i
的类型。
在同等性检查中,由于val (=): 'T -> 'T -> bool
我们还有t(i) = t(0) = int
。
then
分支机构,我们得到另一个约束ty = t(1) = int
。else
分支,普通(*)
运算符为'T -> 'T -> 'T
,因此我们得到t(i) = ty
。 基于约束集:
tx = t(i)
t(i) = t(0) = int
ty = t(1) = int
t(i) = ty
使用统一,我们到达tx = ty = int
并将fact
的类型推断为int -> int
。这也意味着如果你改变if/then/else
中的子句顺序(通过反转条件),类型推断仍然可以正常工作。
那就是说,这是类型推理算法的一个非常简单的例子。 您可以按照上面的维基百科链接阅读更多相关信息。
为了将算法应用于您的自定义语言,您可以在各种函数式编程书籍中找到实现。有关详细信息,请参阅此主题Damas-Hindley-Milner type inference algorithm implementation。