簡體   English   中英

在Scala中,為什么不能在未顯式指定其參數類型的情況下部分應用函數?

[英]In Scala, why can't I partially apply a function without explicitly specifying its argument types?

如您所願,這將產生一個匿名函數(f是具有三個參數的函數):

f(_, _, _)

我不明白的是為什么它不能編譯,而是給出“缺少參數類型”錯誤:

f(_, _, 27)

相反,我需要明確指定下划線的類型。 考慮到函數f的參數類型是什么,Scala是否應該能夠推斷出它們?

以下參考是Scala語言規范

請考慮以下方法:

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)每個參數都是_ (“匿名函數的占位符語法”的特殊情況 (第6.23節))

val f = foo(_, _)   

表達式foo(_, 1)不符合Eta擴展要求; 它只是擴展為(a) => foo(a, 1) (第6.23節)。 常規類型推斷不會嘗試找出a: Int

如果您正在考慮部分應用程序,我認為這只能通過多個參數列表來實現 (而您只有一個):

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 _

我認為這是因為重載使編譯器無法推斷類型:

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>

我認為這是所有代碼轉換引起的邊界情況之一,因為這涉及創建匿名函數,該函數將調用定向到原始方法。 類型用於外部匿名函數的參數。 實際上,您可以指定任何子類型,即

val f = foo(_: Nothing, 1) 

即使這樣會編譯

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM