Answers:
有关Go的类型推断,请参见此StackOverflow答案。我不熟悉Go自己,但基于此答案,这似乎是一种单向的“类型推导”(借用一些C ++术语)。这意味着如果您具有:
x := y + z
然后x通过找出的类型来推导的类型y + z,这对于编译器而言是一件相对琐碎的事情。要做到这一点,其种类y和z需要了解的先验:这可以通过类型注释完成或分配给他们的文字推断。
相反,大多数功能语言具有类型推断功能,该类型推断功能使用模块(或函数,如果推断算法是局部的)中的所有可能信息来得出变量的类型。复杂的推理算法(例如Hindley-Milner)通常在幕后涉及某种形式的类型统一(有点像求解方程式)。例如,在Haskell中,如果您编写:
let x = y + z
然后哈斯克尔可以推断不仅种类x,而且y与z基于您正在执行的加入对他们其实根本。在这种情况下:
x :: Num a => a
y :: Num a => a
z :: Num a => a
(a这里的小写字母表示多态类型,在其他语言(如C ++)中通常称为“泛型”。该Num a =>部分是约束,表明类型a支持具有某些加法概念。)
这是一个更有趣的示例:允许定义任何递归函数的定点组合器:
let fix f = f (fix f)
请注意,我们在哪里都没有指定的类型f,也没有指定的类型fix,但是Haskell编译器可以自动找出:
f :: t -> t
fix :: (t -> t) -> t
这样说:
f必须是从任意类型t到相同类型的函数t。fix是接收类型参数t -> t并返回类型结果的函数t。Go中的类型推断非常有限且非常简单。它仅在一种语言构造(变量声明)中起作用,并且仅采用右侧的类型并将其用作左侧变量的类型。
Haskell中的类型推断可在任何地方使用,它可用于推断整个程序的类型。它基于统一,这意味着(从概念上来说)所有类型都是“一次”推断的,并且它们都可以相互影响:在Go中,类型信息只能从变量声明的右侧流向左侧,另一方面,永远不要在另一个方向,永远不要在变量声明之外;在Haskell中,类型信息在整个程序中向各个方向自由流动。
但是,Haskell的类型系统是如此强大,以至于类型推断实际上无法推断出类型(或更准确地说:必须施加限制,以便始终可以推断出类型)。Go的类型系统非常简单(没有子类型,没有参数多态性),其推理如此有限,以至于它总是成功。
x,y,z都是一样的Num埃里克类型,但他们仍然可以IntegerS,DoubleS,Ratio IntegerS ^ ... Haskell是愿意做数字类型之间任意选择,但不支持其他类型类。