Pertanyaan Di Scala, mengapa saya tidak dapat menerapkan sebagian fungsi tanpa secara eksplisit menentukan jenis argumennya?


Ini menghasilkan fungsi anonim, seperti yang Anda harapkan (f adalah fungsi dengan tiga argumen):

f(_, _, _)

Apa yang saya tidak mengerti adalah mengapa ini tidak dikompilasi, bukannya memberikan kesalahan "tipe parameter yang hilang":

f(_, _, 27)

Sebaliknya, saya perlu menentukan jenis garis bawah secara eksplisit. Seharusnya Scala tidak dapat menyimpulkan mereka mengingat bahwa ia tahu apa jenis parameter fungsi f?


32
2018-03-02 12:24


asal


Jawaban:


Referensi di bawah ini adalah untuk Spesifikasi Bahasa Scala

Pertimbangkan metode berikut:

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

Ekspansi Eta dapat mengkonversikan ini ke nilai jenis (Int, Int) => Int. Perluasan ini dipanggil jika:

Sebuah) _ digunakan sebagai pengganti daftar argumen (Method Value (§6.7))

val f = foo _

b) daftar argumen dihilangkan, dan jenis ekspresi yang diharapkan adalah tipe fungsi (§6.25.2):

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

c) masing-masing argumen adalah _ (Sebuah kasus spesial dari 'Placeholder Syntax for Anonymous Functions' (§6.23))

val f = foo(_, _)   

Ekspresi, foo(_, 1) tidak memenuhi syarat untuk Ekspansi Eta; itu hanya meluas (a) => foo(a, 1) (§6.23). Inferensi tipe biasa tidak mencoba untuk mencari tahu itu a: Int.


17
2018-03-06 20:51



Jika Anda berpikir tentang aplikasi parsial, saya berpikir bahwa ini hanya mungkin dengan beberapa daftar parameter (sedangkan Anda hanya memiliki satu):

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

Contoh Anda menarik karena saya sama sekali tidak menyadari sintaks yang Anda jelaskan dan tampaknya Anda dapat memiliki aplikasi parsial dengan daftar parameter tunggal:

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

Jadi kompilator dapat dengan jelas menyimpulkan tipe 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,_)
                            ^

Hmmm, aneh! Saya sepertinya tidak bisa melakukan aplikasi parsial dengan daftar parameter tunggal. Tapi kemudian jika saya menyatakan jenis parameter kedua, saya bisa memiliki aplikasi parsial!

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

scala> anon2(24)
res2: Int = 44

EDIT - satu hal yang saya amati adalah bahwa sepertinya dua pemendekan berikut ini setara, dalam hal ini sedikit lebih jelas bahwa ini bukan "aplikasi parsial" tetapi lebih seperti "pointer fungsi"

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

8
2018-03-02 12:44



Saya pikir itu karena overloading membuat mustahil bagi compiler untuk menyimpulkan tipe:

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>

1
2017-09-22 12:34



Saya merasa ini adalah salah satu kasus perbatasan yang timbul dari semua konversi kode, karena ini melibatkan penciptaan fungsi anonim yang mengarahkan panggilan ke metode asli. Jenisnya adalah untuk argumen fungsi anonim luar. Sebenarnya, Anda dapat menentukan sub-jenis apa pun

val f = foo(_: Nothing, 1) 

bahkan ini akan dikompilasi


-3
2018-03-07 20:49