tutorial software fungicida examples blanquerna scala

software - En Scala, ¿por qué no puedo aplicar parcialmente una función sin especificar explícitamente sus tipos de argumentos?



scala vs java (4)

Creo que es porque la sobrecarga hace que sea imposible para el compilador inferir los tipos:

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>

Esto produce una función anónima, como era de esperar (f es una función con tres argumentos):

f(_, _, _)

Lo que no entiendo es por qué esto no se compila, sino que aparece un error de "tipo de parámetro faltante":

f(_, _, 27)

En cambio, necesito especificar los tipos de guiones bajos explícitamente. ¿No debería Scala ser capaz de inferirlos dado que sabe cuáles son los tipos de parámetros de la función f?


Las referencias a continuación son para la especificación del lenguaje Scala

Considera el siguiente método:

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

Eta Expansion puede convertir esto a un valor de tipo (Int, Int) => Int . Esta expansión se invoca si:

a) _ se usa en lugar de la lista de argumentos (Method Value (§6.7))

val f = foo _

b) se omite la lista de argumentos, y el tipo de expresión esperado es un tipo de función (§6.25.2):

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

c) cada uno de los argumentos es _ (un caso especial de la ''Sintaxis de marcador de posición para funciones anónimas'' (§6.23))

val f = foo(_, _)

La expresión, foo(_, 1) no califica para Eta Expansion; simplemente se expande a (a) => foo(a, 1) (§6.23). La inferencia de tipo regular no intenta descubrir que a: Int .


Si está pensando en la aplicación parcial, pensé que esto solo era posible con listas de parámetros múltiples (mientras que usted solo tiene una):

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

Sin embargo, su ejemplo es interesante ya que desconocía por completo la sintaxis que describe y parece que puede tener una aplicación parcial con una sola lista de parámetros:

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

Entonces el compilador puede inferir claramente el tipo 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, ¡extraño! No parece poder hacer una aplicación parcial con una sola lista de parámetros. ¡Pero si declaro el tipo del segundo parámetro, puedo tener una aplicación parcial!

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

EDITAR - una cosa que observaría es que parece que las siguientes dos shortenings son equivalentes, en cuyo caso es un poco más obvio que esto no es una "aplicación parcial" sino más bien un "puntero de función"

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


Siento que este es uno de esos casos límite que surgen de la conversión de todos los códigos, ya que esto implica la creación de una función anónima que dirige la llamada al método original. El tipo es para el argumento de la función anónima externa. De hecho, puede especificar cualquier subtipo, es decir,

val f = foo(_: Nothing, 1)

incluso esto compilaría