Scala’s for
comprehension allows filtering:
// plain Scala
for {
x <- (1 to 50).toList if x.toString contains '7'
} yield x
// res0: List[Int] = List(7, 17, 27, 37, 47)
Here’s the typeclass contract for `FunctorFilter`:
@typeclass
trait FunctorFilter[F[_]] extends Serializable {
def functor: Functor[F]
def mapFilter[A, B](fa: F[A])(f: A => Option[B]): F[B]
def collect[A, B](fa: F[A])(f: PartialFunction[A, B]): F[B] =
mapFilter(fa)(f.lift)
def flattenOption[A](fa: F[Option[A]]): F[A] =
mapFilter(fa)(identity)
def filter[A](fa: F[A])(f: A => Boolean): F[A] =
mapFilter(fa)(a => if (f(a)) Some(a) else None)
def filterNot[A](fa: F[A])(f: A => Boolean): F[A] =
mapFilter(fa)(Some(_).filterNot(f))
}
We can use this like this:
import cats._, cats.syntax.all._
val english = Map(1 -> "one", 3 -> "three", 10 -> "ten")
// english: Map[Int, String] = Map(1 -> "one", 3 -> "three", 10 -> "ten")
(1 to 50).toList mapFilter { english.get(_) }
// res1: List[String] = List("one", "three", "ten")
def collectEnglish[F[_]: FunctorFilter](f: F[Int]): F[String] =
f collect {
case 1 => "one"
case 3 => "three"
case 10 => "ten"
}
collectEnglish((1 to 50).toList)
// res2: List[String] = List("one", "three", "ten")
def filterSeven[F[_]: FunctorFilter](f: F[Int]): F[Int] =
f filter { _.show contains '7' }
filterSeven((1 to 50).toList)
// res3: List[Int] = List(7, 17, 27, 37, 47)