Scala函数扩展时缺失参数类型

9
以下代码无法编译:
def f[T](conv: Option[String => T]) {}
f(Some(_.toInt))

使用 <console>:13: error: missing parameter type for expanded function ((x$1) => x$1.toInt) 报错,显式类型声明可以解决问题:

scala> f(Some((x: String) => x.toInt))

为什么编译器不能在这里推断字符串类型?是否存在某种歧义?

通常情况下,是否有可能手动检查和检查从下划线扩展生成的代码?


@slouc,将其发布为答案-这是正确的。如果OP创建了一些涉及String的变异或继承的类型类,那么在某些情况下可能会推断出它,但否则您只需传递一些ClassWithoutToInt,并且它无法使用下划线推断。 - sebszyller
@sebszyller我刚刚删除了我的评论,因为我认为它是错误的:)那么你如何解释这样一个事实,即如果没有Option,也就是说,如果方法只接受一个函数String => T,你可以传递f(_.toInt),它会起作用? - slouc
1
@slouc 我不知道你的答案是什么,但希望我的回答能解释为什么它会起作用。 - Alexey Romanov
SO 抱怨没有足够的问题被提出。我同意,按照常识,这应该是可以解决的。当然,我可能有很好的理由错了。 - som-snytt
1
在REPL中使用f(_.toInt) // show,或者-Xprint:typer来查看类型检查器如何看待你的代码。 - som-snytt
1个回答

5
我认为基本问题在于当输入 Some(_.toInt) 时,编译器需要推断 Some.apply[A](x: A) 的类型参数。为此,它首先需要对参数进行类型检查。然后,A 被视为未知类型常量,并作为预期的类型与 _.toInt 进行类型检查。这将失败,因为只有当预期类型为函数类型(或从Scala 2.12开始,为单个抽象方法类型)时,才允许匿名函数不指定参数类型。然后编译器再次尝试将预期类型设置为 undefined,但由于同样的原因而失败。
在这种情况下,预期的返回类型实际上已足够确定类型参数,这样就可以对 _.toInt 进行类型检查,但这并不是设计工作的方式。
如果您需要更详细的信息,请参考 http://scala-lang.org/files/archive/spec/2.11/06-expressions.html 的第6.6、6.23和6.26.4段。

这是slouc的原始答案,扩展了apply插件。在我看来,它很到位。 - sebszyller
2
匿名函数只有在由预期类型给出时才允许不指定参数类型。"when they are given by the expected type" 是什么意思? - Yuval Itzchakov
虽然我不是6.26.4的专家,但我认为匿名函数无法将变量贡献给约束条件并不明显:Some[b](_.toInt) <: Option[String => a]Some[b](c => Int) <: Option[String => undefined]。参数会被类型检查,期望的类型已经确定(但类型参数已固定)。因此,我们的直觉是这只是一个限制。 - som-snytt
是的,我的意思是第一个问题:我不知道为什么它停止了,没有尝试解决c。(或者为什么它没有引入c。)同样,是的,f[Int]可以工作,因为Some[a](_.toInt)与期望的Option[String => Int]进行了类型检查。期望的类型是如何传播约束的。这是从规范中阅读出来的,而不是从代码中。 - som-snytt
@som-snytt 对,但约束只出现在第二步。第一步(“首先使用两种替代方案计算参数表达式dj的类型Sj”)不使用期望的类型,也不涉及任何约束,我认为正是这一步失败了。 - Alexey Romanov
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接