Domanda

Say Ho un metodo che trasforma un (funzione su due elementi) in una (funzione due sequenze):

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

In parole, la funzione risultante prende due sequenze xs e ys, e crea una nuova sequenza costituito da (xs(0) f ys(0), xs(1) f ys(1), ...) Così, per esempio, se è xss Seq(Seq(1,2),Seq(3,4)) e f è (a: Int, b: Int) => a + b, possiamo invocare così:

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

o con una funzione anonima:

xss reduceLeft seqed[Int](_+_)

Questo è abbastanza buono; sarebbe bello per sbarazzarsi del argomento di tipo [Int] ma non vedere come (tutte le idee?).

per farlo sentire un po 'più come il metodo tupled, ho anche provato il modello Enrich-my-library:

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)

Per una funzione di pre-definita questa grande opera, ma è brutto con quelli anonimi

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

C'è un altro modo per riformulare questo in modo che i tipi sono desunti, e posso utilizzare la sintassi qualcosa come:

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

? O sto chiedendo troppo di inferenza di tipo?

È stato utile?

Soluzione 3

Il motivo per cui un tipo di annotazione è necessario

xss reduceLeft seqed[Int](_+_)

ma non in

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

è dovuto alla differenza di requisiti di tipo tra map e reduceLeft.

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

si aspetta reduceLeft seqed per tornare tipo B dove B >: Int. Sembra che quindi il tipo preciso per seqed non può essere conosciuto, quindi dobbiamo fornire l'annotazione. Maggiori informazioni nel questa domanda .

Un modo per superare questo è quello di re-implementare reduceLeft senza il limite inferiore.

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

Prova:

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

Il problema ora è che questo ora non funziona su sottotipi di Seq (ad esempio List), con o senza il parametro [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 si aspetta una funzione di tipo (List[Int], List[Int]) => List[Int]. Poiché Function2 è definito come Function2 [-T1, -T2, +R], (Seq[Int], Seq[Int]) => Seq[Int] non è una sostituzione valida.

Altri suggerimenti

Non è possibile farlo nel modo desiderato, ma guarda Function.tupled, che è una contro-parte a .tupled che risolve questo stesso 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)

Sono abbastanza sicuro che sono chiedere troppo. Inferenza di tipo a Scala va da sinistra a destra , in modo che il tipo di bisogni (_+_) per essere capito prima anche considerando la parte .sedeq. E non c'è abbastanza informazioni là.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top