5

Decir que tengo un método que convierte una (función de dos elementos) en un (función en dos secuencias):La inferencia de tipos de funciones anónimas con Enrich-mi-librería

def seqed[T](f: (T,T) => T): (Seq[T], Seq[T]) => Seq[T] = (_,_).zipped map f 

En palabras, la función resultante toma dos secuencias xs y ys, y crea una nueva secuencia que consiste en (xs(0) f ys(0), xs(1) f ys(1), ...) Así, por ejemplo, si es xssSeq(Seq(1,2),Seq(3,4)) y f es (a: Int, b: Int) => a + b, podemos invocar así:

xss reduceLeft seqed(f)   // Seq(4, 6) 

o con una función anónima:

xss reduceLeft seqed[Int](_+_) 

Esto es bastante bueno; Sería bueno deshacerse del argumento de tipo [Int], pero no veo cómo (¿alguna idea?).

Para hacer que se sienta un poco más como el método tupled, también probé el patrón Enrich-mi-biblioteca:

class SeqFunction[T](f: (T,T) => T) { 
    def seqed: (Seq[T], Seq[T]) => Seq[T] = (_,_).zipped map f 
} 
implicit def seqFunction[T](f: (T,T) => T) = new SeqFunction(f) 

Para una función predefinida esto funciona muy bien, pero es feo, con los anónimos

xss reduceLeft f.seqed 
xss reduceLeft ((_:Int) + (_:Int)).seqed 

¿hay otra manera de que pueda reformular esto para que los tipos se infieren, y puedo usar la sintaxis algo como:

// pseudocode 
xss reduceLeft (_+_).seqed   // ... or failing that 
xss reduceLeft (_+_).seqed[Int] 

? ¿O estoy pidiendo demasiado de tipo de inferencia?

+2

[Aquí] (http://screencasts.chariotsolutions.com/uncovering-the-unknown-principles-of-type-inference-) Daniel Spiewak hizo una presentación sobre los sistemas de tipo y la inferencia de tipo en 'scala' y otros estáticos mecanografiados. Tal vez eso no sea exactamente sobre el tema, pero de todos modos, lo encontré extremadamente interesante. – 4e6

Respuesta

0

La razón por la cual se requiere una anotación de tipo de

xss reduceLeft seqed[Int](_+_) 

pero no en

xs zip ys map Function.tupled(_+_) 

se debe a la diferencia en los requisitos de tipo entre map y reduceLeft.

def reduceLeft [B >: A] (f: (B, A) ⇒ B): B 
def map  [B]  (f: (A) ⇒ B): Seq[B] // simple version! 

reduceLeft espera seqed para volver tipo B donde B >: Int. Parece que, por lo tanto, no se puede conocer el tipo exacto para seqed, por lo que debemos proporcionar la anotación. Más información en this question.

Una forma de solucionar esto es volver a implementar reduceLeft sin el límite inferior.

implicit def withReduceL[T](xs: Seq[T]) = new { 
    def reduceL(f: (T, T) => T) = xs reduceLeft f 
} 

prueba:

scala> Seq(Seq(1,2,3), Seq(2,2,2)) reduceL seqed(_+_) 
res1: Seq[Int] = List(3, 4, 5) 

El problema ahora es que esto ahora no funciona en subtipos de Seq (por ejemplo List), con o sin la [Int] parámetro:

scala> Seq(List(1,2,3), List(2,2,2)) reduceL seqed(_+_) 
<console>:11: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2)) 
       Seq(List(1,2,3), List(2,2,2)) reduceL seqed(_+_) 
                 ^

reduceL espera una función del tipo (List[Int], List[Int]) => List[Int]. Como Function2 se define como Function2 [-T1, -T2, +R], (Seq[Int], Seq[Int]) => Seq[Int] no es una sustitución válida.

4

Estoy bastante seguro de que son pidiendo demasiado. Escriba la inferencia en Scala goes from left to right, por lo que primero debe averiguar el tipo de (_+_) incluso antes de considerar la parte .sedeq. Y no hay suficiente información allí.

5

No puede hacerlo de la manera que desee, pero consulte Function.tupled, que es una contraparte de .tupled que resuelve el mismo problema.

scala> List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled 
<console>:8: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2)) 
       List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled 
               ^
<console>:8: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2)) 
       List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled 
                ^

scala> List(1, 2, 3) zip List(1, 2, 3) map Function.tupled(_ + _) 
res7: List[Int] = List(2, 4, 6) 
+0

La firma de 'Function.tupled' es' def tupled [a1, a2, b] (f: (a1, a2) => b): Tuple2 [a1, a2] => b'. Lo que no puedo averiguar es cómo conoce los tipos de parámetros en el ejemplo anterior, mientras que mi método requiere '[Int]' en 'xss reduceLeft seqed [Int] (_ + _)'. –

Cuestiones relacionadas