在Scala中,为什么我不能在没有明确指定其参数类型的情况下部分应用函数?

vt.*_*vt. 35 scala

这会产生一个匿名函数,正如您所期望的那样(f是一个带有三个参数的函数):

f(_, _, _)
Run Code Online (Sandbox Code Playgroud)

我不明白为什么这不编译,而是给出"缺少参数类型"错误:

f(_, _, 27)
Run Code Online (Sandbox Code Playgroud)

相反,我需要明确指定下划线的类型.Scala不应该能够推断它们,因为它知道函数f的参数类型是什么吗?

ret*_*nym 19

下面的参考资料是Scala语言规范

请考虑以下方法:

def foo(a: Int, b: Int) = 0
Run Code Online (Sandbox Code Playgroud)

Eta Expansion可以将其转换为类型值(Int, Int) => Int.在以下情况下调用此扩展:

a)_用于代替参数列表(方法值(§6.7))

val f = foo _
Run Code Online (Sandbox Code Playgroud)

b)省略参数列表,期望的表达式是函数类型(§6.25.2):

val f: (Int, Int) => Int = foo
Run Code Online (Sandbox Code Playgroud)

c)中每一个的参数是_(一个特例 "的匿名函数占位符语法"的的(§6.23))

val f = foo(_, _)   
Run Code Online (Sandbox Code Playgroud)

表达foo(_, 1)方式不符合Eta Expansion的条件; 它只是扩展到(a) => foo(a, 1)(§6.23).常规类型推断并不试图弄清楚这一点a: Int.

  • "常规类型推断不会试图找出a:Int.".我可以问,为什么?! (10认同)
  • anon函数参数的类型推断,例如`(a)=> foo(a,1)`中的`a`,仅基于期望的类型,而不是基于函数体中参数的用法. (3认同)

oxb*_*kes 8

如果您正在考虑部分应用程序,我认为这只能用于多个参数列表(而您只有一个):

def plus(x: Int)(y: Int) = x + y //x and y in different parameter lists

val plus10 = plus(10) _ //_ indicates partial application

println(plus10(2)) //prints 12
Run Code Online (Sandbox Code Playgroud)

您的示例很有趣,因为我完全不知道您描述的语法,看起来您可以使用单个参数列表进行部分应用:

scala> def plus2(x: Int, y: Int) = x + y
plus2: (x: Int,y: Int)Int

scala> val anon = plus2(_,_)
anon: (Int, Int) => Int = <function2>

scala> anon(3, 4)
res1: Int = 7
Run Code Online (Sandbox Code Playgroud)

所以编译器可以清楚地推断出类型Int!

scala> val anon2 = plus2(20,_)
<console>:5: error: missing parameter type for expanded function ((x$1) => plus2(20, x$1))
       val anon2 = plus2(20,_)
                            ^
Run Code Online (Sandbox Code Playgroud)

嗯,奇怪!我似乎无法使用单个参数列表进行部分应用.但是如果我声明第二个参数的类型,我可以部分应用!

scala> val anon2 = plus2(20,_: Int)
anon2: (Int) => Int = <function1>

scala> anon2(24)
res2: Int = 44
Run Code Online (Sandbox Code Playgroud)

编辑 - 我要观察的一件事是,似乎以下两个缩写是等价的,在这种情况下,这更明显的是,这不是"部分应用程序",而更像是"函数指针"

val anon1 = plus2(_,_)
val anon2 = plus2 _
Run Code Online (Sandbox Code Playgroud)

  • `val f = foo(_,_)`扩展为`val f =(a,b)=> foo(a,b)`,它与部分应用curried函数不完全相同. (3认同)
  • 部分应用不需要curried方法,它适用于任何方法或功能. (3认同)
  • 要回答这个问题,您可以通过编译器中的Infer.scala进行调试:)我同意,这似乎是一个不必要的限制,但scala的类型推断是有意省略的规范,以允许这样的摆动空间. (2认同)