Scala: cross (cartesian) product with multiple sources and heterogeneous types

前端 未结 1 1508
情深已故
情深已故 2021-01-18 09:13

I\'m trying to construct multiple cross products of traversables of different (but each homogeneous) types. The desired return type is a traversable of a tuple with the type

相关标签:
1条回答
  • 2021-01-18 09:55

    I had a go at it and came up with this:

    trait Crosser[A,B,C] {
      def cross( as: Traversable[A], bs: Traversable[B] ): Traversable[C]
    }
    
    trait LowPriorityCrosserImplicits {
      private type T[X] = Traversable[X]
    
      implicit def crosser2[A,B] = new Crosser[A,B,(A,B)] {
        def cross( as: T[A], bs: T[B] ): T[(A,B)] = for { a <- as; b <- bs } yield (a, b)
      }
    }
    
    object Crosser extends LowPriorityCrosserImplicits {
      private type T[X] = Traversable[X]
    
      implicit def crosser3[A,B,C] = new Crosser[(A,B),C,(A,B,C)] {
        def cross( abs: T[(A,B)], cs: T[C] ): T[(A,B,C)] = for { (a,b) <- abs; c <- cs } yield (a, b, c)
      }
    
      implicit def crosser4[A,B,C,D] = new Crosser[(A,B,C),D,(A,B,C,D)] {
        def cross( abcs: T[(A,B,C)], ds: T[D] ): T[(A,B,C,D)] = for { (a,b,c) <- abcs; d <- ds } yield (a, b, c, d)
      }
    
      // and so on ...
    }
    
    implicit class Crossable[A](xs: Traversable[A]) {
      def cross[B,C](ys: Traversable[B])(implicit crosser: Crosser[A,B,C]): Traversable[C] = crosser.cross( xs, ys )
    }
    

    The main idea is to defer the work to a type class (Crosser) and implement all the different arities simply by specialising for Traversables of tuples with the corresponding arity minus one. Some test in the REPL:

    scala> List(1, 2, 3) cross Seq("a", "b") cross Set(0.5, 7.3)
    res10: Traversable[(Int, String, Double)] = List((1,a,0.5), (1,a,7.3), (1,b,0.5), (1,b,7.3), (2,a,0.5), (2,a,7.3), (2,b,0.5), (2,b,7.3), (3,a,0.5), (3,a,7.3), (3,b,0.5), (3,b,7.3))
    
    0 讨论(0)
提交回复
热议问题