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

时间:2010-03-02 12:24:55

标签: scala

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

f(_, _, _)

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

f(_, _, 27)

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

4 个答案:

答案 0 :(得分:18)

以下参考资料是Scala Language Specification

考虑以下方法:

def foo(a: Int, b: Int) = 0

Eta Expansion可以将其转换为(Int, Int) => Int类型的值。如果符合以下条件,则调用此扩展:

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

val f = foo _

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

val f: (Int, Int) => Int = foo

c)每个参数都是_(匿名函数的占位符语法的special case(§6.23))

val f = foo(_, _)   

表达式foo(_, 1)不符合Eta Expansion的条件;它只是扩展到(a) => foo(a, 1)(§6.23)。常规类型推断不会试图找出a: Int

答案 1 :(得分: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

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

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

因此编译器可以清楚地推断类型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,_)
                            ^
嗯,奇怪!我似乎无法使用单个参数列表进行部分应用。但是如果我声明第二个参数的类型,我可以部分应用!

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

scala> anon2(24)
res2: Int = 44

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

val anon1 = plus2(_,_)
val anon2 = plus2 _

答案 2 :(得分:1)

我认为这是因为重载使编译器无法推断出类型:

scala> object Ashkan { def f(a:Int,b:Int) = a; def f(a:Int,b:String) = b; }
defined object Ashkan

scala> Ashkan.f(1,2)
res45: Int = 1

scala> Ashkan.f(1,"Ashkan")
res46: String = Ashkan

scala> val x= Ashkan.f _
<console>:11: error: ambiguous reference to overloaded definition,
both method f in object Ashkan of type (a: Int, b: String)String
and  method f in object Ashkan of type (a: Int, b: Int)Int
match expected type ?
       val x= Ashkan.f _
                     ^

scala> val x= Ashkan.f(_,_)
<console>:11: error: missing parameter type for expanded function ((x$1, x$2) => Ashkan.f(x$1, x$2))
       val x= Ashkan.f(_,_)
                       ^
<console>:11: error: missing parameter type for expanded function ((x$1: <error>, x$2) => Ashkan.f(x$1, x$2))
       val x= Ashkan.f(_,_)
                         ^

scala> val x= Ashkan.f(_,"Akbar")
<console>:11: error: missing parameter type for expanded function ((x$1) => Ashkan.f(x$1, "Akbar"))
       val x= Ashkan.f(_,"Akbar")
                       ^

scala> val x= Ashkan.f(1,_)
<console>:11: error: missing parameter type for expanded function ((x$1) => Ashkan.f(1, x$1))
       val x= Ashkan.f(1,_)
                         ^

scala> val x= Ashkan.f(1,_:String)
x: String => String = <function1>

答案 3 :(得分:-4)

我觉得这是所有代码转换产生的边界情况之一,因为这涉及创建一个匿名函数,该函数将调用指向原始方法。该类型用于外部匿名函数的参数。实际上,您可以指定任何子类型,即

val f = foo(_: Nothing, 1) 

即使这样也会编译

相关问题