The Typelevel ecosystem of libraries for functional programming in Scala provides several fundamental type classes for representing the capabilities of different computations.
Effect: Transforming the value inside an effect by mapping over it
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
Effect: Putting a value into an effect
trait Applicative[F[_]] extends Functor[F] {
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
def pure[A](x: A): F[A]
}
Effect: Composing multiple effectful computations together sequentially, such that each is dependent on the previous
trait Monad[F[_]] extends Applicative[F] {
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
}
Effect: Raising and handling errors
trait MonadError[F[_], E] with Monad[F] {
def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A]
def rethrow[A, EE <: E](fa: F[Either[EE, A]]): F[A]
}
Effect: Delay the creation of a value
- Defer is a type class that shows the ability to defer creation inside of the type constructor F
trait Defer[F[_]] {
def defer[A](fa: => F[A]): F[A]
}
Effect: Resource safety, guarantee finalizers will run on cancelation
trait MonadCancel[F[_], E] extends MonadError[F, E] {
def bracket[A, B](acquire: F[A])(use: A => F[B])(release: A => F[Unit]): F[B]
def uncancelable[A](body: Poll[F] => F[A]): F[A]
def canceled: F[Unit]
}
Effect: Parallel evaluation
- Provides Fiber
- Best used to implement the Parallel typeclass
trait GenSpawn[F[_], E] extends MonadCancel[F, E] {
def start[A](fa: F[A]): F[Fiber[F, E, A]]
def never[A]: F[A]
def cede: F[Unit]
}
Spawn
is defined astype Spawn[F[_]] = GenSpawn[F, Throwable]
Effect: State sharing between parallel processes
trait GenConcurrent[F[_], E] extends GenSpawn[F, E] {
def ref[A](a: A): F[Ref[F, A]]
def deferred[A]: F[Deferred[F, A]]
def memoize[A](fa: F[A]): F[F[A]]
}
Concurrent
is defined astype Concurrent[F[_]] = GenConcurrent[F, Throwable]
Effect: Measuring time
trait Clock[F[_]] {
def monotonic: F[FiniteDuration]
def realTime: F[FiniteDuration]
}
Effect: Interactions with time, include current time and sleeping
trait GenTemporal[F[_], E] extends GenConcurrent[F, E] with Clock[F] {
def sleep(time: Duration): F[Unit]
}
Temporal
is defined astype Temporal[F[_]] = GenTemporal[F, Throwable]
Effect: Safe capture of side-effects which return values
trait Sync[F[_]] extends MonadCancel[F, Throwable] with Clock[F] with Defer[F] {
def suspend[A](hint: Sync.Type)(thunk: => A): F[A]
}
Effect: Safe capture of side-effects which invoke a callback
trait Async[F[_]] extends Sync[F] with Temporal[F] {
def async[A](k: (Either[Throwable, A] => Unit) => F[Option[F[Unit]]]): F[A]
def async_[A](k: (Either[Throwable, A] => Unit) => Unit): F[A]
}