Frage

Sagen Sie, ich habe eine Methode, die eine (Funktion auf zwei Elementen) in eine (Funktion auf zwei Sequenzen) verwandelt:

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

In Worten erfordert die resultierende Funktion zwei Sequenzen xs und ys, und erzeugt eine neue Sequenz aus (xs(0) f ys(0), xs(1) f ys(1), ...)Also zum Beispiel, wenn xss ist Seq(Seq(1,2),Seq(3,4)) und f ist (a: Int, b: Int) => a + b, Wir können es so aufrufen:

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

oder mit einer anonymen Funktion:

xss reduceLeft seqed[Int](_+_)

Das ist ziemlich gut; Es wäre schön, das loszuwerden [Int] Geben Sie Argument ein, aber ich sehe nicht wie (irgendwelche Ideen?).

Damit es sich ein bisschen mehr wie das anfühlt tupled Methode habe ich auch das AnAnrich-My-Library-Muster ausprobiert:

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)

Für eine vordefinierte Funktion funktioniert dies hervorragend, aber es ist hässlich mit anonymen

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

Gibt es eine andere Möglichkeit, dies neu formulieren, damit die Typen abgeleitet werden, und ich kann Syntax so etwas wie folgt:

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

? Oder frage ich zu viel Typ -Inferenz?

War es hilfreich?

Lösung 3

Der Grund, warum eine Typanentwicklung erforderlich ist in

xss reduceLeft seqed[Int](_+_)

aber nicht in

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

ist auf den Unterschied in den Typanforderungen zwischen dem zwischen map und reduceLeft.

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

reduceLeft erwartet seqed Typ zurückgeben B wo B >: Int. Es scheint daher der genaue Typ für seqed Kann nicht bekannt sein, also müssen wir die Annotation bereitstellen. Weitere Informationen in diese Frage.

Eine Möglichkeit, dies zu überwinden, besteht darin, erneut zu implementieren reduceLeft ohne die untere Grenze.

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

Prüfen:

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

Das Problem ist nun, dass dies jetzt nicht auf Subtypen von funktioniert Seq (z.B List), mit oder ohne die [Int] Parameter:

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 erwartet eine Funktion des Typs (List[Int], List[Int]) => List[Int]. Da Function2 ist definiert als Function2 [-T1, -T2, +R], (Seq[Int], Seq[Int]) => Seq[Int] ist keine gültige Substitution.

Andere Tipps

Sie können es nicht so machen, wie Sie es wollen, aber schauen Sie sich an Function.tupled, was eine Gegenpartie ist zu .tupled Das löst das gleiche Problem.

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)

Ich bin mir ziemlich sicher, dass du dich bist sind zu viel fragen. Geben Sie Inferenz in Scala ein geht von links nach rechts, so die Art von (_+_) muss zuerst herausgefunden werden .sedeq Teil. Und dort sind nicht genügend Informationen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top