1. FunctorFilter

FunctorFilter 

Scala の for 内包表記はフィルタリングができる:

// plain Scala

for {
  x
<- (1 to 50).toList if x.toString contains '7'
} yield x
// res0: List[Int] = List(7, 17, 27, 37, 47)

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))
}

このように使うことができる:

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)