I have some code that uses Monix Observable
for stream processing of a file. To test this code, I'd like for the operations I do on the Observable
to be type independent so I can also perform them on any other data structure like List
. That why I have written the following code to abstract the underlying data structure:
def permutations[F[_] : Applicative : FunctorFilter : SemigroupK](chars: F[Char]): F[F[Char]] = {
Range.inclusive('a', 'z').map(_.toChar)
.map { c ⇒
FunctorFilter[F].filter(chars)(Character.toLowerCase _ andThen (_ != c))
}
.map(Applicative[F].pure)
.reduceLeft(SemigroupK[F].combineK)
}
The thing that bugs me, is that this code creates a lot of intermediary data-structures. Is there a type-class I could use that makes this process more efficient? Something that lifts one data-structure into another without too much overhead, like LiftIO
but for collections of items?
It does not look like cats has anything to offer for this. And monix is not better, it only implements a handful of typeclasses from cats.
So, my best guess would be defining such typeclasses yourself:
import monix.execution.Scheduler.Implicits.global
import cats._
import cats.implicits._
import monix.reactive._
object Test {
def main(args: Array[String]): Unit = {
println(permutations(List('a', 'b', 'c')))
permutations(Observable('a', 'b', 'c')).foreach{c =>
print("Observable(")
c.foreach(c1 => print(c1 + " "))
print(") ")
}
}
def permutations[F[_] : Applicative](chars: F[Char])(implicit seq: Sequence[F], fil: Filter[F]): F[F[Char]] = {
val abc = seq.fromIterable(
Range.inclusive('a', 'z').map(_.toChar)
)
abc.map(c => fil.filter(chars)(_ != c))
}
trait Sequence[F[_]] {
def fromIterable[A](f: Iterable[A]): F[A]
}
implicit val listSequence: Sequence[List] = new Sequence[List] {
def fromIterable[A](f: Iterable[A]): List[A] = f.toList
}
implicit val observableSequence: Sequence[Observable] = new Sequence[Observable] {
def fromIterable[A](f: Iterable[A]): Observable[A] = Observable.fromIterable(f)
}
trait Filter[F[_]] {
def filter[A](fa: F[A])(f: A => Boolean): F[A]
}
implicit val observableFilterFunctor: Filter[Observable] = new Filter[Observable] {
def filter[A](fa: Observable[A])(f: A => Boolean): Observable[A] =
fa.filter(f)
}
implicit val listFilterFunctor: Filter[List] = new Filter[List] {
def filter[A](fa: List[A])(f: A => Boolean): List[A] =
fa.filter(f)
}
}
Result:
List(List(b, c), List(a, c), List(a, b), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c), List(a, b, c))
Observable(b c ) Observable(a c ) Observable(a b ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c ) Observable(a b c )
I sadly couldn't get this to work on scalafiddle or scastie, because both don't offer the correct cats (1.5.0
) and monix (3.0.0-M3
) versions.
I still hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With