Higher Kinded type

A higher-kinded type which is also called a type constructor describes types that require a type to be a concrete type.

An example is the Option data type:

val something:  Option =  ??? // not a valid type
val otherthing : Option[Int] = ??? // valid type 

Same goes for list, futures e.t.c

Functors

A functor captures the notion of something you can map over, changing its
“contents” (or output) but not the structure itself.
The type signature of map on higher kinded types F[A] is:

def mapB : F[B]

Applicatives

An applicative functor, also known as applicative, is a functor that can transform
multiple structures, not just one.
Imagine, we have a number of Option[Int] and we want to perform some sort of operation all of them in a functional manner, we could do that
using a for loop:

val opt1 = Option(1)
val opt2 = Option(2)
val opt3 = Option(3)

val result = for {
  a <- opt1 
  b <- opt2 
  c <- opt3 
} yield a + b + c

But with an applicative functor, we can combine the operations using one of the mapN methods.

val result = (opt1,opt2,opt3).mapN((a,b,c) => a + b + c)

or simply

val result = (opt1,opt2,opt3).mapN(_ + _ +_ )

We’ve done the same thing with less lines of code. The applicative functor has enabled us to combine multiple F[A]

Monads

A monad is a mechanism for sequencing computations: this computation happens after that computation. Roughly speaking, a monad provides a flatMap method for a context F[A]:

def flatMap[B](f: A => F[B]): F[B]

The for comprehension as well know is just syntactic sugar for nested flatMap calls

Effects can be composed using the flatMap method.