kir*_*uku 44 haskell scala type-inference
Haskell的类型推理引擎比Scala强大得多.在Haskell中,我很少需要显式地编写类型,而在Scala中,类型只能在表达式中推断,而不能在方法定义中推断.
例如,请参阅以下Haskell代码段:
size xs = loop xs 0
where
loop [] acc = acc
loop (_ : xs) acc = loop xs (acc+1)
Run Code Online (Sandbox Code Playgroud)
它返回List的大小.Haskell编译器可以识别使用的类型和函数定义.等效的Scala代码:
def size[A]: List[A] => Int = xs => {
def loop: (List[A], Int) => Int = {
case (Nil, acc) => acc
case (_ :: xs, acc) => loop(xs, acc+1)
}
loop(xs, 0)
}
Run Code Online (Sandbox Code Playgroud)
或者使用方法定义:
def size[A](xs: List[A]) = {
def loop(xs: List[A], acc: Int): Int = xs match {
case Nil => acc
case _ :: xs => loop(xs, acc+1)
}
loop(xs, 0)
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么我不能像下面这样写它们?
def size = xs => {
def loop = {
case (Nil, acc) => acc
case (_ :: xs, acc) => loop(xs, acc+1)
}
loop(xs, 0)
}
Run Code Online (Sandbox Code Playgroud)
再次使用方法定义:
def size(xs) = {
def loop(xs, acc) = xs match {
case Nil => acc
case _ :: xs => loop(xs, acc+1)
}
loop(xs, 0)
}
Run Code Online (Sandbox Code Playgroud)
是因为没有人实现它吗?Scala的类型系统不是像这种情况所需的那么强大吗?还是有其他原因吗?
ham*_*mar 54
主要原因是Scala的类型系统允许子类型,这是Hindley-Milner类型推理算法不支持的.
Haskell没有子类型,因此算法在那里工作得更好,尽管GHC支持的许多流行类型系统扩展导致类型推断再次失败,迫使您为某些表达式提供显式类型签名.
最后,它是类型系统的功能和可以完成的类型推断量之间的权衡.Scala和Haskell只是做出了不同的权衡.
Kip*_*ros 24
我想已经给出了主要原因,但我发现Scala的创建者Martin Odersky引用的这句话特别有用,
Scala没有Hindley/Milner类型推断的原因是很难将其与诸如重载(ad-hoc变体,而不是类型类),记录选择和子类型等功能结合起来.我不是说不可能 - 存在许多包含这些功能的扩展; 事实上,我自己也是其中一些人.我只是说在实践中很难使这项工作很好,需要有小型表达式和良好的错误信息.这也不是一个关闭案例 - 许多研究人员正在努力推动这里的界限(例如在Remy的MLF中查看).但是现在,它是更好的类型推理与更好地支持这些功能的权衡.你可以两种方式进行权衡.我们想要与Java集成的事实倾向于支持子类型和远离Hindley/Milner.
来源:发表评论通用类型推断是一件坏事.
Owe*_*wen 19
哈马尔给出了最大的理由.这是另外两个:
考虑
def foo(x) = x.a + x.b
Run Code Online (Sandbox Code Playgroud)
Scala怎么可能推断出论证的类型?它应该寻找与每个类a
和b
领域?如果超过1怎么办?在哈斯克尔
foo x = (a x) + (b x)
Run Code Online (Sandbox Code Playgroud)
记录名称是唯一的,它提出了自己的问题,但意味着您可以随时推断出所引用的记录类型.
case
Scala中的表达式可以是异构的在Scala中,匹配对象的类型可以用作匹配的一部分,也可以决定应该如何进行匹配.因此,即使所有构造函数case
都是for List
,您可能希望将除列表之外的其他内容传递给它,并使其失败.