Golang / Haskell中的类型推断


9

我已经读过,从ML或Haskell之类的功能语言的意义上讲,Go实际上没有真正的类型推断,但是我无法找到一个简单易懂的两个版本的比较。有人可以用基本术语解释Go中的类型推断与Haskell中的类型推断有何不同,以及每种方法的优缺点吗?

Answers:


13

有关Go的类型推断,请参见此StackOverflow答案。我不熟悉Go自己,但基于此答案,这似乎是一种单向的“类型推导”(借用一些C ++术语)。这意味着如果您具有:

x := y + z

然后x通过找出的类型来推导的类型y + z,这对于编译器而言是一件相对琐碎的事情。要做到这一点,其种类yz需要了解的先验:这可以通过类型注释完成或分配给他们的文字推断。


相反,大多数功能语言具有类型推断功能,该类型推断功能使用模块(或函数,如果推断算法是局部的)中的所有可能信息来得出变量的类型。复杂的推理算法(例如Hindley-Milner)通常在幕后涉及某种形式的类型统一(有点像求解方程式)。例如,在Haskell中,如果您编写:

let x = y + z

然后哈斯克尔可以推断不仅种类x,而且yz基于您正在执行的加入对他们其实根本。在这种情况下:

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

4
更确切地说,哈斯克尔可以告诉大家xyz都是一样的Num埃里克类型,但他们仍然可以IntegerS,DoubleS,Ratio IntegerS ^ ... Haskell是愿意做数字类型之间任意选择,但不支持其他类型类。
约翰·德沃夏克

7

Go中的类型推断非常有限且非常简单。它仅在一种语言构造(变量声明)中起作用,并且仅采用右侧的类型并将其用作左侧变量的类型。

Haskell中的类型推断可在任何地方使用,它可用于推断整个程序的类型。它基于统一,这意味着(从概念上来说)所有类型都是“一次”推断的,并且它们都可以相互影响:在Go中,类型信息只能从变量声明的右侧流向左侧,另一方面,永远不要在另一个方向,永远不要在变量声明之外;在Haskell中,类型信息在整个程序中向各个方向自由流动。

但是,Haskell的类型系统是如此强大,以至于类型推断实际上无法推断出类型(或更准确地说:必须施加限制,以便始终可以推断出类型)。Go的类型系统非常简单(没有子类型,没有参数多态性),其推理如此有限,以至于它总是成功。


4
“在Haskell中,类型信息在整个程序中自由地流向各个方向”:我发现这提供了很好的直觉。+1
乔治

在上一段中此答案提出的主张有些误导。Haskell没有子类型。此外,参数多态性不会对类型推断的完整性造成任何问题:关于多态Lambda微积分的Hindley-Milner总是找到最通用的类​​型。Haskell可能无法推断类型,但这将基于复杂的类型系统功能(如GADT),其中,如果天真地表述不存在任何主体(即“最佳选择”)类型。
Edward Z. Yang
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.