简体   繁体   English

为什么Scala不推导出特征类型参数?

[英]Why Scala doesn't deduce trait type parameters?

trait foo[F] {
  def test: F
}

class ah extends foo[(Int,Int) => Int] {
  def test = (i: Int,j: Int) => i+j
}

So the question is, why Scala known to be so smart about types cannot just deduce type (Int,Int) => Int from the type of test asking me instead to specify it? 所以现在的问题是,为什么斯卡拉知道这么聪明类型不能只是演绎型(Int,Int) => Int从类型test问我,而不是指定它? Or It is still possible? 或者仍有可能吗? Or maybe this is backed by some thoughts that I don't have in mind. 或许这可以得到一些我没有想到的想法的支持。

Your question is basically "why does Scala have only local type inference" or equivalently "why does Scala not have non-local type inference". 您的问题基本上是“为什么Scala只有本地类型推断”或等效“为什么Scala没有非本地类型推断”。 And the answer is: because the designers don't want to. 答案是:因为设计师不愿意。

There are several reasons for this. 有几个原因。 One reason is that the most reasonable alternative to local type inference is global type inference, but that's impossible in Scala: Scala has separate compilation and modular type checking, so there simply is no point in time where the compiler has a global view of the entire program. 一个原因是本地类型推断的最合理的替代方法是全局类型推断,但在Scala中这是不可能的:Scala具有单独的编译和模块类型检查,因此编译器只有整个全局视图的时间点。程序。 In fact, Scala has dynamic code loading, which means that at compile time the entire code doesn't even need to exist yet! 实际上,Scala具有动态代码加载功能,这意味着在编译时整个代码甚至不需要存在! Global type inference is simply impossible in Scala. 在Scala中根本不可能进行全局类型推断。 The best we could do is "whole-compilation-unit type inference", but that is undesirable, too: it would mean that whether or not you need type annotations depends on whether or not you compile your code in multiple units or just one. 我们能做的最好的事情是“整个编译单元类型推断”,但这也是不可取的:它意味着你是否需要类型注释取决于你是否在多个单元中编译代码或只编译一个。

Another important reason is that type annotations at module boundaries serve as a double-check, kind of like double-entry book keeping for types. 另一个重要原因是模块边界处的类型注释用作复核,类似于类型的复式簿记。 Note that even in languages with global type inference like Haskell, it is strongly recommended to put type annotations on module boundaries and public interfaces. 请注意,即使在具有全局类型推断的语言如Haskell)中,强烈建议在模块边界和公共接口上放置类型注释。

A third reason is that global type inference can sometimes lead to confusing error messages, when instead of the type checker failing at a type annotation, the type inferencer happily chugs along inferring increasingly non-sensical types, until it finally gives up at a location far away from the actual error (which might just be a simple typo) with a type error that is only tangentially related to the original types at the error site. 第三个原因是全局类型推断有时会导致混淆的错误消息,当类型检查器在类型注释中失败时,类型推断器会快速地推断出越来越不合理的类型,直到它最终放弃到远处的位置。远离实际错误(可能只是一个简单的错字),其类型错误只与错误站点的原始类型相切。 This can sometimes happen in Haskell, for example. 例如,这有时会发生在Haskell中。 The Scala designers value helpful error messages so much that they are willing to sacrifice language features unless they can figure out how to implement them with good error messages. Scala设计人员非常重视有用的错误消息,以至于他们愿意牺牲语言功能,除非他们能够弄清楚如何使用良好的错误消息来实现它们。 (Note that even with Scala's very limited type inference, you can get such "helpful" messages as "expected Foo got Product with Serializable ".) (请注意,即使使用Scala非常有限的类型推断,您也可以获得“有用的”消息,因为“预期Foo得到了Product with Serializable ”。)

However, what Scala's local type inference can do in this example, is to work in the other direction, and infer the parameter types of the anonymous function from the return type of test : 但是,Scala的本地类型推断在此示例中可以执行的操作是在另一个方向上工作,并从返回类型的test推断出匿名函数的参数类型:

trait foo[F] {
  def test: F
}

class ah extends foo[(Int, Int) ⇒ Int] {
  def test = (i, j) ⇒ i + j
}

(new ah) test(2, 3) //=> 5

For you particular example, inferring type parameters based on inheritance can be ambiguous: 对于您的特定示例,基于继承推断类型参数可能不明确:

trait A
trait B extends A

trait Foo[T] {
    val x: T
}

trait Bar extends Foo[?] {
    val x: B
}

The type that could go in the ? 可以进入的类型? could be either A or B . 可以是AB This is a general example of where Scala will not infer types that could be ambiguous. 这是Scala不会推断可能含糊不清的类型的一般示例。

Now, you are correct to observe that there is a similarity between 现在,您正确地观察到它们之间存在相似性

class Foo[T](x: T)

and

trait Foo[T] { x: T }

I have seen work by some into possibly generalizing the similarity (but I can't seem to find it right now). 我看到一些人的工作可能会推广相似性(但我现在似乎无法找到它)。 That could, in theory, allow type inference of type parameters based on a member. 从理论上讲,这可以允许基于成员对类型参数进行类型推断。 But I don't know if it will ever get to that point. 但我不知道它是否会达到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么scala不推断继承特征的类型成员? - Why doesn't scala infer the type members of an inherited trait? 为什么scala不会从泛型类型参数中推断出类型? - Why scala doesn't infer type from generic type parameters? 为什么scala无法从特征中识别方法 - Why scala doesn't recognize method from trait 为什么在嵌套类型参数时 Scala 不能完全推断类型参数? - Why doesn't Scala fully infer type parameters when type parameters are nested? 联合类型绑定到特征的类型参数(scala) - Union types as bound for type parameters of a trait (scala) 为什么Scala在我的抽象类中不能以相同的方式推断类型参数? - Why doesn't Scala infer type parameters the same way in my abstract class? 当其中一个类型参数应该是Nothing时,为什么Scala的隐式类不起作用? - Why doesn't Scala's implicit class work when one of the type parameters should be Nothing? 为什么未对此Scala代码进行类型检查 - Why this Scala code doesn't type checked scala - 特征成员中更高种类的类型:_$1 没有类型参数,预期:1 - scala - Higher kinded type in trait member: _$1 takes no type parameters, expected: 1 为什么你不能在scala中实例化一个特征? - Why can't you instantiate a trait in scala?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM