Próbuję skonstruować wiele produktów krzyżowych z materiałami traserskimi różnych (ale każdy homogeniczny) typów. Żądany typ zwrotu to ruchoma krotka z typem pasującym do typów w wejściowych przejściach. Na przykład:Scala: produkt krzyżowy (kartezjański) z wieloma źródłami i heterogenicznymi typami.
List(1, 2, 3) cross Seq("a", "b") cross Set(0.5, 7.3)
To powinno dać Traversable[(Int, String, Double)]
ze wszystkimi możliwymi kombinacjami z trzech źródeł. Przypadek połączenia tylko dwóch źródeł był ładnie answered here. Dany pomysł jest:
implicit class Crossable[X](xs: Traversable[X]) {
def cross[A](ys: Traversable[A]) = for { x <- xs; y <- ys } yield (x, y)
}
Uwagi tam pokrótce problem większej liczby źródeł, ale szukam, aby znaleźć rozwiązanie, które nie zależą albo bezkształtne lub scalaz (z drugiej strony, I don” t mind o pewnej płycie do skali do Tuple22
). Co chciałbym zrobić coś jak następuje:
implicit class Crossable[X](xs: Traversable[X]) {
def cross[A](ys: Traversable[A]) = for { x <- xs; y <- ys } yield (x, y)
def cross[A,B](ys: Traversable[(A,B)]) = // ... extend all Tuple2's in ys with x in xs to Tuple3's
def cross[A,B,C](ys: Traversable[(A,B,C)]) = // ...
// ...
}
To oczywiście nie działa ze względu na typ skasowaniem (i, niestety, prawdopodobnie wymagać, aby użyć nawiasów w powyższym przykładzie, ponieważ cross
byłoby prawo asocjacyjne).
Moje pytanie brzmi: czy w jakiś sposób można wykorzystać funkcje odbicia Scala 2.10, aby rozwiązać problem? Ogólnie rzecz biorąc, dopasowanie obu typów krotek (i ich parametrów typu, co wydaje się wyzwaniem) i połączenie ich z większymi krotkami powinno zapewnić rozwiązanie satysfakcjonujące asocjacyjne prawo, prawda?
Wow, to jest całkiem fajne! Dziękuję Ci bardzo! Dodanie prawych wersji asocjacyjnych również wydaje się proste dzięki temu podejściu. Zauważyłem, że pozbyłeś się "niejednoznacznych" błędów kompilatora, wprowadzając 'crosser2' w cechę (która w przeciwnym razie zawsze by pasowała). Zakładam, że dla implicite musi istnieć jakaś reguła priorytetu hierarchii zależnej od klasy? Co wciąż mnie zastanawia: dlaczego 'crosser2',' crosser3', ... faktycznie w zakresie? Spodziewałem się, że będę musiał "zaimportować Crosser._", aby wprowadzić je w zakres, ale wydaje się, że tak nie jest. – bluenote10
Na wypadek, gdyby ktoś chciał z tego skorzystać: właśnie napisałem mały generator kodu (muszę nauczyć się makr) i przesłałem [Gist] (https://gist.github.com/bluenote10/5465957#file-crossproduct-scala) zawierająca wszystkie dane z zestawu do racjonalnie wysokiego poziomu (począwszy od parametru 19 typu otrzymałem dziwne błędy kompilatora, ale 18 powinno być dla mnie więcej niż wystarczające). – bluenote10
Powodem, dla którego nie musisz wykonywać "importu Crosser._", jest to, że 'Crosser' jest przekazywany niejawnie w' Crossable.cross', a domyślne reguły rozdzielczości mówią, że podczas wyszukiwania niejawnej wartości typu 'T ', kompilator automatycznie przejrzy elementy obiektu towarzyszącego' T' (jeśli istnieje). Zobacz SLS 7.2 –