2013-03-29 14 views
6

Ich habe versucht, herauszufinden, wie man eine funktionale Swap-Funktion, die auf einem Traversable[_] funktioniert, eine Sammlung und die Indizes zu tauschen. Ich kam mit der folgenden auf:Enrich-My-Library Für alle Traversables

def swap[A, CC <% Traversable[A]](xs: CC, i: Int, j: Int): Traversable[A] = { 
    xs.slice(0, i) ++ 
    xs.slice(j, j+1) ++ 
    xs.slice(i+1, j) ++ 
    xs.slice(i, i+1) ++ 
    xs.slice(j+1, xs.size) 
} 

swap(List(1,2,3,4,5), 0, 4) // => List(5,2,3,4,1) 

Ich mag gerne wissen, wie diese in einer impliziten Erweiterung machen von Travers, die es mir ermöglicht es zu nennen mit List(1,2,3,4,5).swap(0, 4). Der nächste, den ich bekommen konnte, war der folgende:

import language.implicitConversions 
class RichTraversable[A, B <% Traversable[A]](xs: B) { 
    def swap(i: Int, j: Int): Traversable[A] = { 
    xs.slice(0, i) ++ 
     xs.slice(j, j+1) ++ 
     xs.slice(i+1, j) ++ 
     xs.slice(i, i+1) ++ 
     xs.slice(j+1, xs.size) 
    } 
} 
implicit def richTraversable[A, B <% Traversable[A]](ys: B)(implicit b: Traversable[A]) 
    = new RichTraversable[A, B](ys) 

Leider ist das nicht ganz so. Aufruf List(1,2,3,4,5).swap(0, 4) Ergebnisse in dem folgenden Fehler:

error: No implicit view available from List[Int] => Traversable[A]

Ich glaube, ich muss etwas oder erheblich zu verkomplizieren das Problem fehlen. Weiß jemand wie das aufgebaut sein soll?


Hinweis: Dies ist rein akademisch, und nicht in irgendeiner Art und Weise in einer Produktionsumgebung eingesetzt werden. Ich versuche, Scala's Typsystem und Grenzen besser in den Griff zu bekommen.

Antwort

4

Wenn Sie mit Scala 2.10:

import scala.collection.generic.CanBuildFrom 
import scala.collection.TraversableLike 

implicit class TraversableWithSwap[A, Repr <: Traversable[A]](val xs: TraversableLike[A, Repr]) extends AnyVal { 
    def swap[That](i: Int, j: Int)(implicit bf: CanBuildFrom[Repr, A, That]): That = { 
    val builder = bf(xs.asInstanceOf[Repr]) 
    builder.sizeHint(xs) 
    builder ++= xs.take(i) 
    builder ++= xs.slice(j, j + 1) 
    builder ++= xs.slice(i + 1, j) 
    builder ++= xs.slice(i, i + 1) 
    builder ++= xs.drop(j + 1) 
    builder.result 
    } 
} 

(Die AnyVal Sache verwandelt es in einen Value Klasse, was bedeutet, dass der Compiler es als eine statische Funktion umschreiben tatsächlich tun die Verpackung während der Laufzeit zu vermeiden .)

eine frühere Version, fallen die extends AnyVal und verwendet eine implizite-Umwandlungsfunktion statt implicit class Bei Verwendung:

implicit def toTraversableWithSwap[A, Repr <: Traversable[A]](xs: TraversableLike[A, Repr]) = new TraversableWithSwap(xs) 

und deren Verwendung:

scala> Vector(1,2,3,4,5,6,7,8,9).swap(2,5) 
res0: scala.collection.immutable.Vector[Int] = Vector(1, 2, 6, 4, 5, 3, 7, 8, 9) 

Beachten Sie, dass es nicht wirklich sinnvoll ist, diese Funktion zu definieren, für alle Traversable seit einigen traversables (wie Set, Map, usw.) sind ungeordnete, zwei Elemente so Swapping ist sinnlos . Sie würden es wahrscheinlich wirklich für alle Seq oder so etwas definieren wollen.

Auch: Können wir uns auch einfach darauf verständigen, es bereits "enhance-my-library" zu nennen?

+0

Erstens: Woah, was ist das für ein Baumeister, den ich noch nie gesehen habe? Und zweitens: Ja, wir können zustimmen, es von nun an zu nennen =) – KChaloux

+0

Der Builder ist, was in den internen Sammlungen verwendet wird. Siehe zum Beispiel: https://github.com/scala/scala/blob/master/src/library/scala/collection/TraversableLike.scala#L237 – dhg

+0

Hmm. Ich kann es nicht finden, CanBuildFrom oder TraversableLike zu finden. Gibt es einen Import, den ich vermisse? – KChaloux