Pregunta

Digamos que tengo un método que convierte una (función en dos elementos) en un (función en dos secuencias):

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), ...)Entonces, por ejemplo, si xss es Seq(Seq(1,2),Seq(3,4)) y f es (a: Int, b: Int) => a + b, podemos invocarlo 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 [Int] Escriba argumento pero no veo cómo (¿alguna idea?).

Para que se sienta un poco más como el tupled Método, también probé el patrón enriquecano-my-bibrary:

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 forma en que pueda reformular esto para que los tipos se infieran, y puedo usar sintaxis algo así como:

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

? ¿O estoy pidiendo demasiada inferencia de tipo?

¿Fue útil?

Solución 3

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

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 esperanza seqed para devolver el tipo B dónde B >: Int. Parece que por lo tanto el tipo preciso para seqed no se puede conocer, por lo que tenemos que proporcionar la anotación. Más información en esta pregunta.

Una forma de superar 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 (p.ej List), con o sin el [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 de tipo (List[Int], List[Int]) => List[Int]. Porque Function2 Se define como Function2 [-T1, -T2, +R], (Seq[Int], Seq[Int]) => Seq[Int] no es una sustitución válida.

Otros consejos

No puedes hacerlo como quieres, pero mira Function.tupled, que es una contraparte para .tupled Eso resuelve este 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)

Estoy bastante seguro de que tu son Pidiendo demasiado. Tipo de inferencia en Scala va de izquierda a derecha, entonces el tipo de (_+_) necesita ser resuelto primero antes de considerar el .sedeq parte. Y no hay suficiente información allí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top