2013-03-29 12 views
6

Próbowałem dowiedzieć się, jak napisać funkcjonalną funkcję wymiany, która działa na każdym Traversable[_], biorąc pod uwagę kolekcję i indeksy do zamiany. Wpadłem poniżej:Wzbogacić-Moja-Biblioteka Dla wszystkich 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) 

Chciałbym wiedzieć, jak zrobić to w sposób dorozumiany przedłużenie przesuwny, umożliwiając mi nazwać z List(1,2,3,4,5).swap(0, 4). Najbliższe, jakie mogłem uzyskać, to:

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) 

Niestety to nie wszystko. Wywołanie List(1,2,3,4,5).swap(0, 4) wyniki w następujący błąd:

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

czuję musi być czegoś brakuje, lub znacznie nadmiernie komplikuje sprawę. Czy ktokolwiek wie, jak powinno to wyglądać?


Uwaga: To jest czysto akademicki, i nie jest używana w środowisku produkcyjnym w jakikolwiek sposób. Próbuję uzyskać lepszą kontrolę nad systemem typu Scala i ograniczeniami.

Odpowiedz

4

Jeśli używasz 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 
    } 
} 

(AnyVal rzecz zamienia ją w klasy wartości, co oznacza, że ​​kompilator będzie przepisać go jako funkcję statycznego, aby uniknąć robi zawijanie podczas wykonywania faktycznie .)

przypadku korzystania z wcześniejszej wersji, upuścić extends AnyVal i użyć funkcji niejawny-konwersji zamiast implicit class:

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

i używając go:

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) 

Zauważ, że faktycznie nie ma sensu, aby zdefiniować tę funkcję dla wszystkich Traversable od niektórych traversables (jak Set, Map, etc) są nieuporządkowane, więc zamiana dwóch elementów nie ma sensu . Prawdopodobnie chciałbyś zdefiniować go dla wszystkich Seq lub coś podobnego.

Również: Czy możemy po prostu zgodzić się nazwać to "ulepszeniem mojej biblioteki"?

+0

Po pierwsze: Woah, co to jest budowniczy, którego nigdy wcześniej nie widziałem? I drugie: tak, możemy zgodzić się nazwać to od teraz =) – KChaloux

+0

Konstruktor jest tym, co jest używane w wewnętrznych kolekcjach. Zobacz na przykład: https://github.com/scala/scala/blob/master/src/library/scala/collection/TraversableLike.scala#L237 – dhg

+0

Hmm. Nie mogę go znaleźć, aby znaleźć CanBuildFrom lub TraversableLike. Czy brakuje mi importu? – KChaloux

Powiązane problemy