Question

Say I ai une méthode qui transforme un (fonction sur deux éléments) dans une (fonction de deux séquences):

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

En d'autres termes, la fonction résultante prend deux séquences xs et ys, et crée une nouvelle séquence consistant en (xs(0) f ys(0), xs(1) f ys(1), ...) Ainsi, par exemple, si xss est Seq(Seq(1,2),Seq(3,4)) et f est (a: Int, b: Int) => a + b, nous pouvons invoquons ainsi:

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

ou avec une fonction anonyme:

xss reduceLeft seqed[Int](_+_)

Ceci est assez bon; ce serait bien de se débarrasser de l'argument de type [Int] mais je ne vois pas comment (des idées?).

Pour faire sentir un peu plus comme la méthode tupled, j'ai essayé aussi le modèle d'Enrich-ma bibliothèque:

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)

Pour une fonction prédéfinie cela fonctionne très bien, mais il est moche avec les anonymes

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

Y at-il une autre façon, je peux reformuler cela pour que les types sont inférées, et je peux utiliser quelque chose comme la syntaxe:

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

? Ou que je demande trop d'inférence de type?

Était-ce utile?

La solution 3

La raison pour laquelle une annotation de type est nécessaire

xss reduceLeft seqed[Int](_+_)

mais pas dans

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

est due à la différence dans les exigences de type entre map et reduceLeft.

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

reduceLeft attend seqed retourner le type BB >: Int. Il semble donc que le type précis de seqed ne peut pas être connu, donc nous devons fournir l'annotation. Plus d'infos sur cette question.

Une façon de surmonter ce problème est de re-mettre en œuvre reduceLeft sans la limite inférieure.

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

Test:

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

Le problème est maintenant que cela ne maintenant pas le travail sur les sous-types de Seq (par exemple List), avec ou sans le paramètre [Int]:

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 attend une fonction de type (List[Int], List[Int]) => List[Int]. Parce que Function2 est défini comme Function2 [-T1, -T2, +R], (Seq[Int], Seq[Int]) => Seq[Int] ne remplace pas valide.

Autres conseils

Vous ne pouvez pas le faire de la façon dont vous voulez, mais regardez Function.tupled, qui est une contre-partie à .tupled qui permet de résoudre ce problème même.

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)

Je suis assez sûr que vous sont trop demander. L'inférence de type à Scala va de gauche à droite , de sorte que le type de besoins de (_+_) à être compris d'abord avant même de considérer la partie .sedeq. Et il n'y a pas assez d'informations.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top